Code Reusability Standards
Before you build anything — check if it already exists. When to extract to a shared component, hook, service, or function.
Before you build anything, ask: "Does this already exist, or will it exist again?" If the answer is yes to either, build it once, build it properly, and reuse it everywhere.
This standard helps decide when UI, logic, validation, services, and platform patterns should become shared assets instead of one-off implementations.
1. Reusability Check Before You Build
Run this check on every task before writing a single line of code or rebuilding an interface block.
If any answer is yes, stop and extract before you build.
2. Reusability Decision Rule
| Situation | Decision |
|---|---|
| Used in 2 or more places right now | Must be reusable |
| Will clearly be used again soon | Build reusable from the start |
| Complex logic with a clear purpose | Extract to a named function |
| You're copy-pasting from another file | Stop. Extract first. |
| Identical UI component used on two pages | Shared component |
| Same API call pattern in multiple files | Shared service or hook |
| Same validation rules in Add and Edit | Shared validation schema |
| Same error handling logic repeated | Shared error handler |
| Three or more similar lines doing the same pattern | Extract to function |
Three or more similar lines means automatic extraction.
3. React / Next.js Reusability
React projects become hard to maintain fast when shared UI, API logic, and validation rules live inline in feature files. Keep the reusable parts in predictable folders and use the same component or schema across the same flow.
What to Make Reusable
| Item | Where It Lives | Example |
|---|---|---|
| Shared UI component | components/ui/ |
Button.tsx, Input.tsx, Modal.tsx |
| Feature-specific component | components/[feature]/ |
ProjectCard.tsx, MemberList.tsx |
| Shared form | components/forms/ |
ProjectForm.tsx (used in Add + Edit) |
| Custom hook | hooks/ |
useProjects.ts, useAuth.ts |
| API call logic | services/ or lib/ |
projects.service.ts |
| Validation schema | validations/ |
project.schema.ts |
| Error handler | utils/api-error-handler.ts |
Used across all API calls |
| Constants and enums | constants/ |
roles.ts, status.ts |
| Type definitions | types/ |
Project.ts, User.ts |
Folder Structure
src/
components/
ui/
Button.tsx
Input.tsx
Modal.tsx
Table.tsx
Badge.tsx
forms/
ProjectForm.tsx ← Used in Add Project AND Edit Project
MemberInviteForm.tsx
modals/
DeleteConfirmModal.tsx
ConfirmActionModal.tsx
hooks/
useProjects.ts
useWorkspace.ts
useAuth.ts
services/
projects.service.ts
members.service.ts
auth.service.ts
validations/
project.schema.ts
member.schema.ts
utils/
api-error-handler.ts
date-formatter.ts
string-utils.ts
constants/
roles.ts
status.ts
routes.ts
types/
project.ts
user.ts
workspace.ts
Anti-Patterns
× Same Button component defined in 5 different files.
× ProjectForm duplicated in AddProject.tsx and EditProject.tsx with different validation.
× fetch('/api/projects') called directly in 8 different components.
× Same error handling logic copy-pasted across every form submit handler.
× Validation rules written inline in each form component.
4. WeWeb Reusability
In WeWeb, reusability means treating recurring UI and behavior as reusable elements, named collections, and shared design tokens instead of rebuilding them per page.
What to Make Reusable
| Item | Where It Lives |
|---|---|
| Header / Navbar | Reusable Element |
| Footer | Reusable Element |
| Sidebar | Reusable Element |
| Card component | Reusable Element |
| Form section | Reusable Element |
| Modal / Popup | Reusable Element |
| API call | Named Collection or Action |
| Global variables | WeWeb Global Variables |
| Color/typography | WeWeb Global Design Styles |
WeWeb Reusability Rules
Naming Reusable Elements
| Good | Bad |
|---|---|
Card — Project |
Group 4 |
Modal — Delete Confirmation |
Popup copy |
Header — Authenticated |
Header thing |
Form — Invite Member |
Section 2 |
5. Xano Reusability
In Xano, extraction usually means moving repeated multi-step endpoint logic into named functions so permission checks, formatting, logging, and validation stay consistent.
What to Make Reusable
| Item | Where It Lives |
|---|---|
| Auth/permission check | Xano Function: check_workspace_permission |
| Slug generator | Xano Function: generate_slug |
| Email sender | Xano Function: send_email |
| Date formatter | Xano Function: format_date |
| Price calculator | Xano Function: calculate_invoice_total |
| Pagination logic | Xano Function: paginate_query |
| Webhook signature check | Xano Function: verify_webhook_signature |
Rule
If you write the same 3+ steps in two different Xano endpoints — extract to a function.
6. Django Reusability
Django work should keep views thin and move repeatable business rules, validation, and template fragments into the layers that are meant to be shared.
What to Make Reusable
| Item | Where It Lives | Example |
|---|---|---|
| Business logic | services.py or managers.py |
ProjectService.create_project() |
| Reusable queries | managers.py |
Project.objects.active() |
| Permission mixin | mixins.py |
WorkspaceMemberMixin |
| Reusable form | forms.py |
ProjectForm (used in create + update views) |
| Template component | templates/components/ |
card.html, form_field.html |
| Template filter | templatetags/ |
{{ date|format_date }} |
| Shared validation | validators.py |
validate_phone_number() |
| Utility functions | utils.py |
generate_slug(), send_notification() |
Fat Models, Thin Views Rule
View: Handle the HTTP request and response. Not more.
Model/Service: Handle the business logic.
Form/Serializer: Handle validation.
Template: Handle display only.
Bad — business logic in view:
def create_project(request):
name = request.POST.get('name')
slug = name.lower().replace(' ', '-')
existing = Project.objects.filter(slug=slug, workspace=workspace).first()
if existing:
...
Project.objects.create(name=name, slug=slug, workspace=workspace, created_by=request.user)
send_email(...)
log_audit(...)
Good — logic extracted to service:
# services/project_service.py
class ProjectService:
@staticmethod
def create_project(workspace, name, created_by):
slug = generate_slug(name)
if Project.objects.filter(slug=slug, workspace=workspace).exists():
raise ConflictError('Project name already exists.')
project = Project.objects.create(name=name, slug=slug, workspace=workspace, created_by=created_by)
send_notification(created_by, 'project_created', project)
AuditLog.log('project.created', actor=created_by, entity=project)
return project
# views.py
def create_project(request):
form = ProjectForm(request.POST)
if not form.is_valid():
return error_response(form.errors)
project = ProjectService.create_project(
workspace=request.workspace,
name=form.cleaned_data['name'],
created_by=request.user
)
return success_response(project)
7. Supabase Reusability
Supabase reusability shows up in RPC functions, consistent RLS patterns, shared query shapes, and database-level validation that multiple clients can trust.
What to Make Reusable
| Item | Where It Lives |
|---|---|
| Complex multi-step operations | RPC / Postgres Function |
| Repeated RLS patterns | Consistent policy templates |
| Common query patterns | Postgres Views or Functions |
| Validation logic | DB check constraints + RPC |
| Audit logging | DB trigger |
| Workspace membership check | Consistent subquery pattern |
Reusable RPC Pattern
If the same business operation happens in multiple places (e.g., "create project + create default task + create activity log"), put it in one RPC function — not in three separate frontend calls.
Bad:
// Frontend makes 3 sequential calls
await supabase.from('projects').insert(...)
await supabase.from('tasks').insert(...)
await supabase.from('activity_logs').insert(...)
Good:
// Frontend makes 1 call, backend handles the rest
await supabase.rpc('create_project_with_defaults', { p_workspace_id, p_name })
8. Naming Conventions for Functions
Names must be clear enough that another team member knows what the reusable item does without reading its internal code.
verb_noun or getVerb (for getters)
| Good | Bad |
|---|---|
formatDate(date) |
dateHelper(d) |
generateSlug(name) |
makeSlug(n) |
validatePhoneNumber(phone) |
checkPhone(p) |
calculateInvoiceTotal(items) |
doCalc(stuff) |
sendEmailNotification(user, template) |
sendEmail(u, t) |
9. Naming Conventions for Components
PascalCase, named by what it IS
| Good | Bad |
|---|---|
ProjectCard |
Card2 |
DeleteConfirmModal |
Popup |
MemberInviteForm |
FormComponent |
WorkspaceSelector |
Dropdown |
10. Naming Conventions for Hooks
useNoun or useVerbNoun
| Good | Bad |
|---|---|
useProjects |
useData |
useWorkspaceMembers |
useMembers2 |
useProjectForm |
useForm |
11. Naming Conventions for Services
noun.service.ts / NounService
| Good | Bad |
|---|---|
projects.service.ts |
api.ts |
ProjectService |
Helper |
12. Reusability Anti-Patterns
These are the most common violations. Watch for all of them.
| Anti-Pattern | Impact | Fix |
|---|---|---|
| Same component markup in 5 files | One change breaks inconsistently | Extract to shared component |
| Add form and Edit form have different validation | Users can bypass validation on edit | Shared validation schema |
Same fetch call to /projects in 8 components |
Changes require editing 8 files | Shared service/hook |
| Business logic inline in a view function | Cannot reuse, cannot test, grows forever | Extract to service |
| Same 10-line error handler in every form | One fix needed everywhere | Shared handleApiError() util |
| Template section copy-pasted to 4 pages | Update one, forget the rest | {% include %} component |
| Same Xano permission check steps in 12 endpoints | Change once, must update 12 | Xano reusable function |
| WeWeb header rebuilt on every page | Style changes require page-by-page updates | Reusable Element |
Django utility function defined in views.py |
Cannot be used by other views/apps | Move to utils.py |
Hardcoded string "admin" in 20 places |
Rename role → 20 places to update | Constants file |
13. When Not to Over-Abstract
Reusability is good, but over-abstraction creates complexity.
Do not make something reusable if:
× It is only used in one place and has no clear future use.
× Making it "generic" requires more complex parameters than just duplicating it.
× The abstraction would make the code harder to read than the original.
× It is a one-time migration script or throwaway utility.
The rule: Three or more identical uses means extract. One use means keep it local unless the next reuse is obvious.