@wazir-dev/cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
# Performance Anti-Patterns
|
|
2
|
+
|
|
3
|
+
> Performance anti-patterns are coding and architectural mistakes that degrade application speed, responsiveness, and resource efficiency. Unlike functional bugs that produce wrong results, performance anti-patterns produce correct results slowly -- often undetectably slow in development but catastrophically slow in production under real data volumes and traffic. These anti-patterns are uniquely dangerous because they compound: two individually tolerable inefficiencies can combine to make a system unusable.
|
|
4
|
+
|
|
5
|
+
> **Domain:** Performance
|
|
6
|
+
> **Anti-patterns covered:** 21
|
|
7
|
+
> **Highest severity:** Critical
|
|
8
|
+
|
|
9
|
+
## Anti-Patterns
|
|
10
|
+
|
|
11
|
+
### AP-01: The N+1 Query
|
|
12
|
+
|
|
13
|
+
**Also known as:** Select N+1, Lazy Loading Landmine, Query Explosion
|
|
14
|
+
**Frequency:** Very Common
|
|
15
|
+
**Severity:** Critical
|
|
16
|
+
**Detection difficulty:** Hard
|
|
17
|
+
|
|
18
|
+
**What it looks like:**
|
|
19
|
+
Code fetches a list of parent records with one query, then issues a separate query for each parent to fetch related child records. In ORM-based code, this often hides behind lazy-loaded relationships that fire transparently:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
# BAD: 1 query for posts + N queries for authors
|
|
23
|
+
posts = Post.objects.all()
|
|
24
|
+
for post in posts:
|
|
25
|
+
print(post.author.name) # triggers a query per post
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Why developers do it:**
|
|
29
|
+
ORMs make lazy loading the default because it simplifies the API surface. In development with 10 rows, the 11 queries complete in under 50ms and nobody notices. The code reads cleanly and "just works." Developers trust the ORM to be efficient.
|
|
30
|
+
|
|
31
|
+
**What goes wrong:**
|
|
32
|
+
With 10,000 records, a single page load fires 10,001 queries. Each individual query is fast (2-5ms), so none appears in slow-query logs -- but the aggregate wall time exceeds 20 seconds. PlanetScale and Sentry have documented this as the single most common performance issue in web applications. Production databases get hammered with thousands of near-identical queries, exhausting connection pools and degrading performance for all users. A 50x slowdown compared to eager loading is typical: 101 queries at 10ms each = 1,010ms vs. 2 queries at 10ms each = 20ms.
|
|
33
|
+
|
|
34
|
+
**The fix:**
|
|
35
|
+
Use eager loading (JOIN or prefetch) to retrieve related data in bulk:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
# GOOD: 2 queries total regardless of N
|
|
39
|
+
posts = Post.objects.select_related('author').all()
|
|
40
|
+
for post in posts:
|
|
41
|
+
print(post.author.name) # no additional query
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
In GraphQL, use DataLoader to batch and deduplicate. In raw SQL, use JOINs or IN clauses. Set up N+1 detection in your test suite (e.g., django-query-count, bullet gem for Rails).
|
|
45
|
+
|
|
46
|
+
**Detection rule:**
|
|
47
|
+
If a database query executes inside a loop that iterates over the results of another query, this is AP-01. Also suspect if page load fires >50 queries and most share the same structure with different IDs.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### AP-02: Missing Database Indexes
|
|
52
|
+
|
|
53
|
+
**Also known as:** Full Table Scan, Sequential Scan Syndrome
|
|
54
|
+
**Frequency:** Very Common
|
|
55
|
+
**Severity:** Critical
|
|
56
|
+
**Detection difficulty:** Moderate
|
|
57
|
+
|
|
58
|
+
**What it looks like:**
|
|
59
|
+
Queries filter, join, or sort on columns that have no index. The database must scan every row in the table to find matches:
|
|
60
|
+
|
|
61
|
+
```sql
|
|
62
|
+
-- No index on users.email
|
|
63
|
+
SELECT * FROM users WHERE email = 'user@example.com';
|
|
64
|
+
-- Full table scan: O(n) instead of O(log n)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Why developers do it:**
|
|
68
|
+
With small development datasets (hundreds of rows), full table scans are instantaneous. Developers focus on correctness, not query plans. ORM-generated migrations often only create indexes for primary keys and explicit unique constraints. Developers assume the database "figures it out."
|
|
69
|
+
|
|
70
|
+
**What goes wrong:**
|
|
71
|
+
A query that takes 50ms against 1,000 rows takes 3+ seconds against 2 million production rows. Sentry's engineering blog documented this as the most common cause of slow queries in production: developers ship code that works perfectly locally, then alerts fire in production as full table scans consume CPU and I/O. Write performance also degrades as the database locks rows during long scans. A single missing index on a high-traffic endpoint can cascade into connection pool exhaustion and full application downtime.
|
|
72
|
+
|
|
73
|
+
**The fix:**
|
|
74
|
+
Run `EXPLAIN ANALYZE` on every query that touches tables with >10k rows. Add indexes on columns used in WHERE, JOIN ON, and ORDER BY clauses:
|
|
75
|
+
|
|
76
|
+
```sql
|
|
77
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
78
|
+
-- Verify: EXPLAIN shows Index Scan instead of Seq Scan
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Use composite indexes for multi-column filters. Review slow query logs weekly. Add index linting to CI (e.g., `pg_stat_user_tables` for tables with high sequential scan ratios).
|
|
82
|
+
|
|
83
|
+
**Detection rule:**
|
|
84
|
+
If a query plan shows "Seq Scan" or "Full Table Scan" on a table with more than a few thousand rows, this is AP-02. Also suspect if query execution time grows linearly with table size.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
### AP-03: Memory Leaks
|
|
89
|
+
|
|
90
|
+
**Also known as:** Slow Bleed, Creeping OOM, The Weekend Crash
|
|
91
|
+
**Frequency:** Common
|
|
92
|
+
**Severity:** Critical
|
|
93
|
+
**Detection difficulty:** Very Hard
|
|
94
|
+
|
|
95
|
+
**What it looks like:**
|
|
96
|
+
Objects are allocated but never released because references persist beyond their useful lifetime. Common patterns:
|
|
97
|
+
- Event listeners registered but never removed
|
|
98
|
+
- Closures capturing large scopes
|
|
99
|
+
- Growing caches without eviction policies
|
|
100
|
+
- Timers/intervals never cleared
|
|
101
|
+
- Circular references preventing garbage collection
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
// BAD: listener never removed, element reference held forever
|
|
105
|
+
class Component {
|
|
106
|
+
mount() {
|
|
107
|
+
this.handler = (e) => this.handleScroll(e);
|
|
108
|
+
window.addEventListener('scroll', this.handler);
|
|
109
|
+
}
|
|
110
|
+
// No unmount/cleanup method
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Why developers do it:**
|
|
115
|
+
Garbage-collected languages create a false sense of safety -- "the runtime handles memory." Memory leaks in GC'd languages are subtle: the objects are reachable (so the GC correctly keeps them) but no longer needed. The application works fine for hours or days before memory pressure builds.
|
|
116
|
+
|
|
117
|
+
**What goes wrong:**
|
|
118
|
+
Cloudflare's "Cloudbleed" incident (2017) stemmed from a buffer overrun where their edge servers ran past the end of a buffer and returned memory containing private data -- HTTP cookies, authentication tokens, and POST bodies from other users. A .NET order processing service on Kubernetes exhibited a rising memory slope over weeks, eventually triggering OOM restarts; it took six weeks to find the cause -- a lambda capturing a reference to a large object graph. RavenDB documented a production cluster where instances would periodically crash from OOM due to memory fragmentation with `posix_memalign`. The Logstash file input plugin held growing file tracking state that was never released, exhausting host memory on Windows.
|
|
119
|
+
|
|
120
|
+
**The fix:**
|
|
121
|
+
Always pair resource acquisition with cleanup. In JavaScript, remove event listeners in component teardown. In React, return cleanup functions from useEffect. In server code, use bounded caches (LRU) with max-size policies. Monitor memory in production with alerting on growth trends, not just absolute thresholds.
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// GOOD: cleanup on unmount
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const handler = (e) => handleScroll(e);
|
|
127
|
+
window.addEventListener('scroll', handler);
|
|
128
|
+
return () => window.removeEventListener('scroll', handler);
|
|
129
|
+
}, []);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Detection rule:**
|
|
133
|
+
If code adds event listeners, timers, subscriptions, or cache entries without a corresponding removal/cleanup path, this is AP-03. If memory usage grows monotonically under steady load, suspect AP-03.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
### AP-04: Blocking the Main Thread
|
|
138
|
+
|
|
139
|
+
**Also known as:** UI Freeze, ANR (Application Not Responding), Event Loop Starvation
|
|
140
|
+
**Frequency:** Very Common
|
|
141
|
+
**Severity:** Critical
|
|
142
|
+
**Detection difficulty:** Moderate
|
|
143
|
+
|
|
144
|
+
**What it looks like:**
|
|
145
|
+
Synchronous, long-running operations execute on the main/UI thread, preventing the application from responding to user input or processing other events:
|
|
146
|
+
|
|
147
|
+
```javascript
|
|
148
|
+
// BAD: synchronous file read blocks the Node.js event loop
|
|
149
|
+
const data = fs.readFileSync('/large-file.csv');
|
|
150
|
+
processData(data);
|
|
151
|
+
|
|
152
|
+
// BAD: CPU-intensive work on the main thread
|
|
153
|
+
function findPrimes(limit) {
|
|
154
|
+
// blocks everything for seconds
|
|
155
|
+
for (let i = 2; i < limit; i++) { /* ... */ }
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Why developers do it:**
|
|
160
|
+
Synchronous code is simpler to write and reason about. Async patterns (callbacks, promises, async/await) add complexity. In development, the file is small and the computation fast, so blocking is imperceptible. Mobile developers may not realize that all UI work must happen on the main thread, but I/O must not.
|
|
161
|
+
|
|
162
|
+
**What goes wrong:**
|
|
163
|
+
On Android, if the main thread is blocked for more than 5 seconds, the system shows an "Application Not Responding" (ANR) dialog, and the user can force-close the app. In Node.js, Trigger.dev documented event loop lag causing servers to handle as few as 5 requests per second with event loop delays exceeding one minute. Ashby Engineering documented how a single blocking operation in their Node.js backend caused cascading latency for all concurrent users because the event loop couldn't process any other requests while blocked. In browsers, blocking the main thread prevents rendering, making the page appear frozen.
|
|
164
|
+
|
|
165
|
+
**The fix:**
|
|
166
|
+
Move I/O and heavy computation off the main thread. Use async I/O, Web Workers (browser), worker_threads (Node.js), or background threads (mobile):
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
// GOOD: async I/O
|
|
170
|
+
const data = await fs.promises.readFile('/large-file.csv');
|
|
171
|
+
// GOOD: offload CPU work
|
|
172
|
+
const worker = new Worker('./prime-worker.js');
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
On mobile, use coroutines (Kotlin), GCD (Swift), or Isolates (Dart/Flutter) for background work. Enable StrictMode in Android development to catch main-thread I/O.
|
|
176
|
+
|
|
177
|
+
**Detection rule:**
|
|
178
|
+
If synchronous I/O functions (readFileSync, synchronous HTTP requests) appear in server or UI code, this is AP-04. If CPU-intensive loops execute without yielding, suspect AP-04. Monitor event loop lag in Node.js; anything above 100ms indicates blocking.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### AP-05: Layout Thrashing
|
|
183
|
+
|
|
184
|
+
**Also known as:** Forced Synchronous Reflow, Read-Write-Read Storm
|
|
185
|
+
**Frequency:** Common
|
|
186
|
+
**Severity:** High
|
|
187
|
+
**Detection difficulty:** Moderate
|
|
188
|
+
|
|
189
|
+
**What it looks like:**
|
|
190
|
+
JavaScript code alternates between reading and writing layout properties in a tight loop, forcing the browser to recalculate layout on every read:
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
// BAD: read-write cycle forces reflow on every iteration
|
|
194
|
+
const elements = document.querySelectorAll('.item');
|
|
195
|
+
elements.forEach(el => {
|
|
196
|
+
const height = el.offsetHeight; // READ - forces layout
|
|
197
|
+
el.style.height = height + 10 + 'px'; // WRITE - invalidates layout
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Why developers do it:**
|
|
202
|
+
The DOM API makes reading and writing properties look equally cheap. Developers treat `offsetHeight` like reading a variable, not realizing it triggers a full layout recalculation when the layout is dirty. The code is logically correct and works on small DOMs.
|
|
203
|
+
|
|
204
|
+
**What goes wrong:**
|
|
205
|
+
Paul Irish (Google Chrome team) documented a comprehensive list of properties and methods that force layout/reflow. When these are interleaved with writes in a loop, the browser cannot batch layout operations and must perform a full reflow on every read. With hundreds of elements, this drops frame rates from 60fps to single digits. The browser's "Recalculate style" events pile up in the performance timeline as cascading purple blocks. Google's web.dev documentation specifically warns that layout thrashing is one of the most common causes of janky animations and scroll performance.
|
|
206
|
+
|
|
207
|
+
**The fix:**
|
|
208
|
+
Batch all reads first, then all writes. Use `requestAnimationFrame` for DOM writes. Use the FastDOM library for automated read/write batching:
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// GOOD: batch reads, then writes
|
|
212
|
+
const heights = Array.from(elements).map(el => el.offsetHeight);
|
|
213
|
+
elements.forEach((el, i) => {
|
|
214
|
+
el.style.height = heights[i] + 10 + 'px';
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
**Detection rule:**
|
|
219
|
+
If code reads a layout property (offsetHeight, clientWidth, getBoundingClientRect) and writes a style property (style.height, style.width, className) inside the same loop iteration, this is AP-05.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
### AP-06: Unoptimized Images
|
|
224
|
+
|
|
225
|
+
**Also known as:** 5MB Hero Image, The LCP Killer
|
|
226
|
+
**Frequency:** Very Common
|
|
227
|
+
**Severity:** High
|
|
228
|
+
**Detection difficulty:** Easy
|
|
229
|
+
|
|
230
|
+
**What it looks like:**
|
|
231
|
+
Images served in uncompressed formats (BMP, unoptimized PNG), at original camera resolution (4000x3000 for a 400x300 display slot), without responsive sizing, lazy loading, or modern format conversion:
|
|
232
|
+
|
|
233
|
+
```html
|
|
234
|
+
<!-- BAD: 5MB original DSLR photo for a thumbnail -->
|
|
235
|
+
<img src="photo-original.png" />
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Why developers do it:**
|
|
239
|
+
Developers upload the image from the designer or camera and it "looks right." Image optimization is perceived as a build-step concern, not a code concern. Nobody checks the network tab during development because images load instantly from localhost.
|
|
240
|
+
|
|
241
|
+
**What goes wrong:**
|
|
242
|
+
73% of mobile pages use an image as their Largest Contentful Paint (LCP) element. An unoptimized hero image is the single most common cause of LCP failure. MDN and Google's web.dev document that every 1-second delay in LCP can reduce conversion rates by 12%. Only 59% of mobile pages meet the "Good" LCP threshold of 2.5 seconds. A 5MB image that should be 200KB wastes bandwidth, drains mobile data plans, and makes the page feel broken on slow connections.
|
|
243
|
+
|
|
244
|
+
**The fix:**
|
|
245
|
+
Use modern formats (WebP, AVIF), responsive images with `srcset`, proper sizing, compression, and lazy loading for below-the-fold images:
|
|
246
|
+
|
|
247
|
+
```html
|
|
248
|
+
<!-- GOOD: optimized, responsive, lazy-loaded -->
|
|
249
|
+
<img
|
|
250
|
+
src="photo-400w.webp"
|
|
251
|
+
srcset="photo-400w.webp 400w, photo-800w.webp 800w"
|
|
252
|
+
sizes="(max-width: 600px) 400px, 800px"
|
|
253
|
+
loading="lazy"
|
|
254
|
+
alt="Description"
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Use build-time image optimization (sharp, imagemin) or image CDNs (Cloudinary, imgix) for on-the-fly transformation.
|
|
259
|
+
|
|
260
|
+
**Detection rule:**
|
|
261
|
+
If image files exceed 500KB, lack `loading="lazy"` for below-fold images, use PNG/JPEG when WebP/AVIF is viable, or have no `srcset`/`sizes` attributes, this is AP-06.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
### AP-07: No Pagination or Virtual Scrolling
|
|
266
|
+
|
|
267
|
+
**Also known as:** Rendering 10,000 DOM Nodes, The Infinite Scroll of Death
|
|
268
|
+
**Frequency:** Common
|
|
269
|
+
**Severity:** High
|
|
270
|
+
**Detection difficulty:** Easy
|
|
271
|
+
|
|
272
|
+
**What it looks like:**
|
|
273
|
+
Code fetches and renders an entire dataset into the DOM at once, regardless of how many records exist:
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
// BAD: renders all 50,000 items into the DOM
|
|
277
|
+
const items = await fetchAllItems();
|
|
278
|
+
items.forEach(item => {
|
|
279
|
+
const div = document.createElement('div');
|
|
280
|
+
div.textContent = item.name;
|
|
281
|
+
container.appendChild(div);
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Why developers do it:**
|
|
286
|
+
With 20 test records, rendering everything is the simplest approach. Pagination adds UI complexity (page controls, state management). Virtual scrolling requires a library. "It works in dev" syndrome prevails.
|
|
287
|
+
|
|
288
|
+
**What goes wrong:**
|
|
289
|
+
Browsers struggle with more than a few thousand DOM nodes. At 10,000+ nodes, scrolling becomes janky, memory usage balloons, and initial render can take seconds. Mobile devices are hit hardest due to limited memory. The browser must layout, paint, and composite all nodes even if only 20 are visible. React applications rendering large lists without virtualization can consume hundreds of megabytes of memory just for the virtual DOM representation.
|
|
290
|
+
|
|
291
|
+
**The fix:**
|
|
292
|
+
For finite datasets, use pagination (server-side preferred). For scrollable lists, use virtual scrolling libraries that render only visible items plus a small buffer:
|
|
293
|
+
|
|
294
|
+
```javascript
|
|
295
|
+
// GOOD: react-window renders only visible items
|
|
296
|
+
import { FixedSizeList } from 'react-window';
|
|
297
|
+
|
|
298
|
+
<FixedSizeList height={600} itemCount={50000} itemSize={35}>
|
|
299
|
+
{({ index, style }) => <div style={style}>{items[index].name}</div>}
|
|
300
|
+
</FixedSizeList>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Libraries: react-window, react-virtualized, @angular/cdk virtual-scroll, vue-virtual-scroller.
|
|
304
|
+
|
|
305
|
+
**Detection rule:**
|
|
306
|
+
If code renders a list without a limit/offset mechanism and the data source can grow unboundedly, this is AP-07. If the DOM contains >1,000 sibling elements from a single data source, suspect AP-07.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### AP-08: Unnecessary Re-renders
|
|
311
|
+
|
|
312
|
+
**Also known as:** Render Storm, Prop Drilling Cascade, State Thrashing
|
|
313
|
+
**Frequency:** Very Common
|
|
314
|
+
**Severity:** High
|
|
315
|
+
**Detection difficulty:** Hard
|
|
316
|
+
|
|
317
|
+
**What it looks like:**
|
|
318
|
+
UI components re-render when their inputs have not meaningfully changed, because of new object/array references, state lifted too high, or missing memoization:
|
|
319
|
+
|
|
320
|
+
```jsx
|
|
321
|
+
// BAD: new object reference on every parent render
|
|
322
|
+
function Parent() {
|
|
323
|
+
const [count, setCount] = useState(0);
|
|
324
|
+
// This object is recreated every render, causing Child to re-render
|
|
325
|
+
const config = { theme: 'dark' };
|
|
326
|
+
return <Child config={config} onClick={() => setCount(c => c + 1)} />;
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**Why developers do it:**
|
|
331
|
+
Inline objects and arrow functions are the most readable pattern. React's mental model suggests "rendering is cheap" -- and for simple components it is. Developers don't realize that new references defeat `React.memo` and `shouldComponentUpdate`. In development with React DevTools, the extra renders are invisible without profiling.
|
|
332
|
+
|
|
333
|
+
**What goes wrong:**
|
|
334
|
+
When re-renders happen on heavy components (charts, tables, forms with validation), the UI becomes visibly laggy. DebugBear and Kent C. Dodds have documented how unnecessary re-renders degrade Interaction to Next Paint (INP) scores, making applications feel unresponsive. In extreme cases, a single state change at the root can trigger hundreds of component re-renders cascading through the tree, each performing diffing, effect evaluation, and DOM reconciliation. The development build of React is also slower, masking that production will be somewhat better -- but not enough if the fundamental re-render count is excessive.
|
|
335
|
+
|
|
336
|
+
**The fix:**
|
|
337
|
+
Stabilize references with `useMemo` and `useCallback`. Use `React.memo` for expensive components. Move state as close to where it's used as possible. Use context selectors or state management libraries with fine-grained subscriptions:
|
|
338
|
+
|
|
339
|
+
```jsx
|
|
340
|
+
// GOOD: stable references prevent unnecessary re-renders
|
|
341
|
+
function Parent() {
|
|
342
|
+
const [count, setCount] = useState(0);
|
|
343
|
+
const config = useMemo(() => ({ theme: 'dark' }), []);
|
|
344
|
+
const handleClick = useCallback(() => setCount(c => c + 1), []);
|
|
345
|
+
return <Child config={config} onClick={handleClick} />;
|
|
346
|
+
}
|
|
347
|
+
const Child = React.memo(function Child({ config, onClick }) { /* ... */ });
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
**Detection rule:**
|
|
351
|
+
If a component receives non-primitive props (objects, arrays, functions) created inline in the parent's render, this is AP-08. Use React DevTools Profiler "Highlight updates" to visualize unnecessary re-renders.
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### AP-09: Large Bundle Sizes
|
|
356
|
+
|
|
357
|
+
**Also known as:** Ship Everything Upfront, The 2MB JavaScript Bundle
|
|
358
|
+
**Frequency:** Very Common
|
|
359
|
+
**Severity:** High
|
|
360
|
+
**Detection difficulty:** Easy
|
|
361
|
+
|
|
362
|
+
**What it looks like:**
|
|
363
|
+
The entire application is shipped as a single JavaScript bundle with no code splitting. Every page loads every route, every library, and every feature:
|
|
364
|
+
|
|
365
|
+
```javascript
|
|
366
|
+
// BAD: single entry point imports everything
|
|
367
|
+
import { AdminDashboard } from './admin';
|
|
368
|
+
import { UserProfile } from './profile';
|
|
369
|
+
import { Analytics } from './analytics';
|
|
370
|
+
import { moment } from 'moment'; // 300KB for date formatting
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Why developers do it:**
|
|
374
|
+
Code splitting adds configuration complexity (dynamic imports, chunk naming, loading states). Single-bundle builds are the default in many setups. Developers don't monitor bundle size as a metric. Adding a dependency feels free -- `npm install` is easy, but nobody checks that `moment.js` adds 300KB.
|
|
375
|
+
|
|
376
|
+
**What goes wrong:**
|
|
377
|
+
Smashing Magazine and web.dev have documented that large JavaScript bundles delay initial page load because the browser must download, parse, and execute all code before the page becomes interactive. A 2MB bundle on a 3G connection takes 8+ seconds just to download, then additional seconds to parse and execute. This directly impacts Time to Interactive (TTI) and First Input Delay (FID). Users on mobile networks experience blank screens or frozen interfaces. Google's Core Web Vitals penalize these pages in search rankings.
|
|
378
|
+
|
|
379
|
+
**The fix:**
|
|
380
|
+
Use dynamic imports for route-based code splitting. Analyze bundle composition with webpack-bundle-analyzer or source-map-explorer. Replace heavy libraries with lighter alternatives (date-fns instead of moment, preact instead of react for simple use cases):
|
|
381
|
+
|
|
382
|
+
```javascript
|
|
383
|
+
// GOOD: route-based code splitting with dynamic imports
|
|
384
|
+
const AdminDashboard = React.lazy(() => import('./admin'));
|
|
385
|
+
const UserProfile = React.lazy(() => import('./profile'));
|
|
386
|
+
|
|
387
|
+
// GOOD: tree-shakeable imports
|
|
388
|
+
import { format } from 'date-fns'; // only imports what you use
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Set bundle size budgets in CI. Fail builds that exceed thresholds.
|
|
392
|
+
|
|
393
|
+
**Detection rule:**
|
|
394
|
+
If the main JavaScript bundle exceeds 200KB gzipped, this is likely AP-09. If `import` statements pull in entire libraries when only one function is needed, suspect AP-09.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### AP-10: Not Using Connection Pooling
|
|
399
|
+
|
|
400
|
+
**Also known as:** Connect-Per-Request, Connection Churn, Socket Exhaustion
|
|
401
|
+
**Frequency:** Common
|
|
402
|
+
**Severity:** Critical
|
|
403
|
+
**Detection difficulty:** Moderate
|
|
404
|
+
|
|
405
|
+
**What it looks like:**
|
|
406
|
+
Every database or HTTP request creates a new connection, uses it once, and closes it:
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
# BAD: new connection per request
|
|
410
|
+
def get_user(user_id):
|
|
411
|
+
conn = psycopg2.connect(host='db', dbname='app')
|
|
412
|
+
cursor = conn.cursor()
|
|
413
|
+
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
414
|
+
result = cursor.fetchone()
|
|
415
|
+
conn.close()
|
|
416
|
+
return result
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Why developers do it:**
|
|
420
|
+
Creating a connection per request is the simplest pattern and avoids complexity around connection lifecycle management, pool sizing, and stale connection handling. Tutorial code almost always shows single-connection examples. Connection leaks (forgetting to return connections to the pool) are harder to debug than connection-per-request.
|
|
421
|
+
|
|
422
|
+
**What goes wrong:**
|
|
423
|
+
A mobile backend documented by Microsoft experienced authentication failures during peak hours because thousands of short-lived HttpClient instances saturated all available sockets, with the root cause being the overhead of TCP handshake + TLS negotiation (50-200ms) on every request. A .NET application on GitHub Issues (#18089) documented complete database connection pool exhaustion causing 500 errors across the entire application. Each new database connection requires TCP handshake, authentication, and protocol negotiation -- under load, this overhead dominates actual query time. Connection exhaustion cascades: when the database hits max_connections, every service querying that database fails simultaneously.
|
|
424
|
+
|
|
425
|
+
**The fix:**
|
|
426
|
+
Use connection pools for all database and HTTP connections. Configure pool sizes based on load testing. Always return connections to the pool (use context managers / try-finally):
|
|
427
|
+
|
|
428
|
+
```python
|
|
429
|
+
# GOOD: connection pool
|
|
430
|
+
from psycopg2 import pool
|
|
431
|
+
|
|
432
|
+
db_pool = pool.ThreadedConnectionPool(5, 20, host='db', dbname='app')
|
|
433
|
+
|
|
434
|
+
def get_user(user_id):
|
|
435
|
+
conn = db_pool.getconn()
|
|
436
|
+
try:
|
|
437
|
+
cursor = conn.cursor()
|
|
438
|
+
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
439
|
+
return cursor.fetchone()
|
|
440
|
+
finally:
|
|
441
|
+
db_pool.putconn(conn)
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
For HTTP, reuse clients (Python `requests.Session`, Node.js `http.Agent` with `keepAlive: true`, .NET `HttpClientFactory`).
|
|
445
|
+
|
|
446
|
+
**Detection rule:**
|
|
447
|
+
If database or HTTP connection constructors are called inside request handlers or loop bodies, this is AP-10. If "connection refused" or "pool exhausted" errors appear under load, suspect AP-10.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
### AP-11: Excessive Network Requests
|
|
452
|
+
|
|
453
|
+
**Also known as:** Chatty API, Request Waterfall, No Batching
|
|
454
|
+
**Frequency:** Common
|
|
455
|
+
**Severity:** High
|
|
456
|
+
**Detection difficulty:** Moderate
|
|
457
|
+
|
|
458
|
+
**What it looks like:**
|
|
459
|
+
The client makes many small, sequential network requests when a single batched request would suffice. Each request carries HTTP overhead (headers, TLS, round-trip latency):
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
// BAD: 100 individual requests
|
|
463
|
+
const userIds = [1, 2, 3, /* ... 100 ids */];
|
|
464
|
+
const users = await Promise.all(
|
|
465
|
+
userIds.map(id => fetch(`/api/users/${id}`))
|
|
466
|
+
);
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Why developers do it:**
|
|
470
|
+
RESTful API design often maps one resource to one endpoint, making individual fetches the natural pattern. Developers build features incrementally -- first one fetch, then another, then another -- without stepping back to see the aggregate. Batching requires server-side changes that frontend developers may not control.
|
|
471
|
+
|
|
472
|
+
**What goes wrong:**
|
|
473
|
+
Each HTTP request has a minimum overhead of 100-300ms on mobile networks (DNS + TCP + TLS + server processing). 100 sequential requests take 10-30 seconds even if each payload is tiny. Browser connection limits (6 per domain in HTTP/1.1) create queuing. Mobile devices waste battery on radio wake-ups for each request. Server-side, thousands of small requests consume more resources than fewer batched requests due to per-request overhead (authentication, logging, connection handling).
|
|
474
|
+
|
|
475
|
+
**The fix:**
|
|
476
|
+
Batch requests on the client or server. Use GraphQL for flexible data fetching. Implement batch endpoints. Cache aggressively (HTTP cache headers, service workers, in-memory caches):
|
|
477
|
+
|
|
478
|
+
```javascript
|
|
479
|
+
// GOOD: single batched request
|
|
480
|
+
const users = await fetch('/api/users?ids=1,2,3,...100');
|
|
481
|
+
|
|
482
|
+
// GOOD: GraphQL fetches exactly what's needed in one request
|
|
483
|
+
const { data } = await graphqlClient.query({
|
|
484
|
+
query: gql`{ users(ids: [1,2,3]) { id, name, email } }`
|
|
485
|
+
});
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
**Detection rule:**
|
|
489
|
+
If the network tab shows >20 requests to the same API domain during a single user interaction, this is AP-11. If sequential fetches share the same base URL with different IDs, suspect AP-11.
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
### AP-12: Logging in Hot Paths
|
|
494
|
+
|
|
495
|
+
**Also known as:** Verbose Production Logging, Console.log-Driven Development
|
|
496
|
+
**Frequency:** Common
|
|
497
|
+
**Severity:** High
|
|
498
|
+
**Detection difficulty:** Moderate
|
|
499
|
+
|
|
500
|
+
**What it looks like:**
|
|
501
|
+
Debug-level logging statements remain in performance-critical code paths that execute thousands of times per second:
|
|
502
|
+
|
|
503
|
+
```java
|
|
504
|
+
// BAD: logging inside a hot loop
|
|
505
|
+
for (Order order : orders) {
|
|
506
|
+
logger.debug("Processing order: " + order.toJson()); // serialization + I/O on every iteration
|
|
507
|
+
processOrder(order);
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Why developers do it:**
|
|
512
|
+
Logging is added during debugging and never removed. Developers assume "debug level won't run in production" but misconfigure log levels. Even when log level checks prevent output, string concatenation and object serialization may still execute before the level check.
|
|
513
|
+
|
|
514
|
+
**What goes wrong:**
|
|
515
|
+
Benchmarks show stdout-based logging makes hot code paths approximately 5,000x slower, file-based logging approximately 1,500x slower, and buffered file logging approximately 57x slower. Alibaba Cloud engineering documented significant throughput degradation from logging in high-frequency code paths. The overhead comes from three sources: string serialization (converting objects to strings), I/O operations (writing to disk or network), and synchronization (log frameworks often use locks for thread safety). An ASP.NET Core application was documented as feeling fast locally but slow in production specifically due to excessive logging volume.
|
|
516
|
+
|
|
517
|
+
**The fix:**
|
|
518
|
+
Remove logging from hot paths entirely, or use lazy evaluation with level guards:
|
|
519
|
+
|
|
520
|
+
```java
|
|
521
|
+
// GOOD: guard prevents serialization if debug is disabled
|
|
522
|
+
if (logger.isDebugEnabled()) {
|
|
523
|
+
logger.debug("Processing order: {}", order.getId());
|
|
524
|
+
}
|
|
525
|
+
// GOOD: use parameterized messages (no concatenation until needed)
|
|
526
|
+
logger.debug("Processing order: {}", order::getId);
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
Use asynchronous logging frameworks (Log4j2 AsyncAppender, Serilog async sink). Set production log level to INFO or WARN. Never log request/response bodies in production hot paths.
|
|
530
|
+
|
|
531
|
+
**Detection rule:**
|
|
532
|
+
If logging statements (console.log, logger.debug, print) appear inside loops or methods called >100 times/second, this is AP-12. If log output includes serialized objects (toJson, toString) in hot paths, suspect AP-12.
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
### AP-13: Over-Fetching Data
|
|
537
|
+
|
|
538
|
+
**Also known as:** SELECT *, Return Everything, Kitchen Sink Response
|
|
539
|
+
**Frequency:** Very Common
|
|
540
|
+
**Severity:** Medium
|
|
541
|
+
**Detection difficulty:** Easy
|
|
542
|
+
|
|
543
|
+
**What it looks like:**
|
|
544
|
+
APIs and queries return far more data than the client needs. The classic example is `SELECT *` when only two columns are needed, or REST endpoints that return full object graphs when the client needs only a name:
|
|
545
|
+
|
|
546
|
+
```sql
|
|
547
|
+
-- BAD: fetches 50 columns when 2 are needed
|
|
548
|
+
SELECT * FROM users WHERE active = true;
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
```json
|
|
552
|
+
// API returns 4KB per user when client only needs name
|
|
553
|
+
{ "id": 1, "name": "Alice", "email": "...", "address": {...},
|
|
554
|
+
"preferences": {...}, "history": [...], "metadata": {...} }
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Why developers do it:**
|
|
558
|
+
`SELECT *` is easier to write and doesn't break when columns are added. REST API design often returns the full resource representation for consistency. Developers think "better to have data and not need it than need it and not have it." The cost of over-fetching is invisible in development with fast local networks.
|
|
559
|
+
|
|
560
|
+
**What goes wrong:**
|
|
561
|
+
Nordic APIs and multiple engineering blogs document how over-fetching wastes bandwidth on mobile networks, increases response times (serialization, network transfer, deserialization), and forces clients to process and discard unused data. On low-bandwidth or high-latency networks, the extra data causes measurably longer response times. `SELECT *` also prevents covering index optimizations -- the database must read full rows from disk instead of answering from the index alone. At scale, over-fetching multiplies: 100 bytes of unnecessary data per response x 1 million requests/day = 100GB of wasted bandwidth daily.
|
|
562
|
+
|
|
563
|
+
**The fix:**
|
|
564
|
+
Select only needed columns. Design API responses for specific use cases, or use GraphQL for client-specified field selection. Support sparse fieldsets in REST (`?fields=id,name`):
|
|
565
|
+
|
|
566
|
+
```sql
|
|
567
|
+
-- GOOD: fetch only what's needed
|
|
568
|
+
SELECT id, name FROM users WHERE active = true;
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
```javascript
|
|
572
|
+
// GOOD: GraphQL - client specifies exactly what it needs
|
|
573
|
+
query { users(active: true) { id, name } }
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Detection rule:**
|
|
577
|
+
If queries use `SELECT *` or API responses consistently contain fields the consuming client never reads, this is AP-13. Compare API response size to the data actually rendered on screen.
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
### AP-14: Polling When Push Is Available
|
|
582
|
+
|
|
583
|
+
**Also known as:** Are We There Yet?, Busy Waiting, Poll Storm
|
|
584
|
+
**Frequency:** Common
|
|
585
|
+
**Severity:** Medium
|
|
586
|
+
**Detection difficulty:** Easy
|
|
587
|
+
|
|
588
|
+
**What it looks like:**
|
|
589
|
+
The client repeatedly asks the server for updates at fixed intervals, even when server-initiated push mechanisms (WebSockets, SSE, webhooks) are available:
|
|
590
|
+
|
|
591
|
+
```javascript
|
|
592
|
+
// BAD: polling every 2 seconds
|
|
593
|
+
setInterval(async () => {
|
|
594
|
+
const status = await fetch('/api/order/status');
|
|
595
|
+
updateUI(status);
|
|
596
|
+
}, 2000);
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Why developers do it:**
|
|
600
|
+
Polling is the simplest real-time pattern -- it requires no special server infrastructure, works with standard REST APIs, and has no connection management complexity. WebSockets require different server architecture, load balancer configuration, and reconnection logic. HTTP/2 and SSE are less well understood.
|
|
601
|
+
|
|
602
|
+
**What goes wrong:**
|
|
603
|
+
Ably and RxDB have benchmarked the overhead: each poll carries full HTTP header overhead (500+ bytes), TCP setup cost, and server processing -- even when there's no new data (which is the majority of polls). At scale, polling at 2-second intervals means 1,800 requests/hour per client. With 10,000 concurrent users, that's 18 million requests/hour of mostly wasted work. Long polling improves this but still creates strain under scale with rapid message streams. WebSockets handle this with a single persistent connection and push semantics: the server sends data only when something changes, with message frames as small as 2-6 bytes of overhead.
|
|
604
|
+
|
|
605
|
+
**The fix:**
|
|
606
|
+
Use WebSockets for bidirectional real-time communication. Use Server-Sent Events (SSE) for unidirectional server-to-client updates. Use webhooks for server-to-server notifications. Reserve polling for environments where push is truly unavailable:
|
|
607
|
+
|
|
608
|
+
```javascript
|
|
609
|
+
// GOOD: WebSocket - server pushes updates
|
|
610
|
+
const ws = new WebSocket('wss://api.example.com/orders');
|
|
611
|
+
ws.onmessage = (event) => updateUI(JSON.parse(event.data));
|
|
612
|
+
|
|
613
|
+
// GOOD: SSE - simple server push
|
|
614
|
+
const source = new EventSource('/api/order/stream');
|
|
615
|
+
source.onmessage = (event) => updateUI(JSON.parse(event.data));
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
**Detection rule:**
|
|
619
|
+
If `setInterval` or `setTimeout` calls a fetch/HTTP endpoint repeatedly, and the data changes are event-driven on the server, this is AP-14.
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
### AP-15: Not Using a CDN for Static Assets
|
|
624
|
+
|
|
625
|
+
**Also known as:** Origin-Only Serving, Single Point of Latency
|
|
626
|
+
**Frequency:** Common
|
|
627
|
+
**Severity:** Medium
|
|
628
|
+
**Detection difficulty:** Easy
|
|
629
|
+
|
|
630
|
+
**What it looks like:**
|
|
631
|
+
All static assets (JavaScript bundles, CSS, images, fonts) are served directly from the application's origin server, regardless of where the user is located geographically:
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
User in Tokyo → Origin server in Virginia → 200ms round trip per asset
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**Why developers do it:**
|
|
638
|
+
Serving from the origin "just works" with no additional infrastructure. CDN configuration adds complexity (cache invalidation, CORS, SSL). Developers in the same region as the origin server don't experience the latency. Small teams may see CDN costs as unnecessary.
|
|
639
|
+
|
|
640
|
+
**What goes wrong:**
|
|
641
|
+
Cloudflare and DigitalOcean document that CDNs can reduce load times by up to 50% by serving content from edge servers closer to users. Without a CDN, a user 200ms round-trip from the origin server pays that 200ms for every single asset. A page loading 30 static assets sequentially adds 6 seconds of pure network latency. The origin server also bears the full traffic load, making it a single point of failure. DoorDash and Spotify are documented as using CDN infrastructure (Fastly, Cloudflare) specifically because geographic latency at scale directly impacts user engagement.
|
|
642
|
+
|
|
643
|
+
**The fix:**
|
|
644
|
+
Put all static assets behind a CDN. Use cache-busting filenames (content hashes) for aggressive caching. Set long Cache-Control headers for immutable assets:
|
|
645
|
+
|
|
646
|
+
```
|
|
647
|
+
# Nginx: cache static assets with content-hash filenames
|
|
648
|
+
location /static/ {
|
|
649
|
+
expires 1y;
|
|
650
|
+
add_header Cache-Control "public, immutable";
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Use CDN providers (Cloudflare, Fastly, CloudFront, Akamai). Enable Brotli compression at the CDN edge. Use `preconnect` hints for third-party CDN domains.
|
|
655
|
+
|
|
656
|
+
**Detection rule:**
|
|
657
|
+
If static assets (JS, CSS, images, fonts) are served from the same domain as the API with no CDN proxy, this is AP-15. Check response headers for CDN indicators (e.g., `cf-cache-status`, `x-cache`).
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
### AP-16: Quadratic Algorithms Where Linear Exists
|
|
662
|
+
|
|
663
|
+
**Also known as:** Accidental O(n^2), Hidden Nested Loop, The Scaling Cliff
|
|
664
|
+
**Frequency:** Common
|
|
665
|
+
**Severity:** High
|
|
666
|
+
**Detection difficulty:** Hard
|
|
667
|
+
|
|
668
|
+
**What it looks like:**
|
|
669
|
+
Code uses nested loops, repeated array searches, or naive algorithms that scale quadratically when linear or log-linear alternatives exist:
|
|
670
|
+
|
|
671
|
+
```javascript
|
|
672
|
+
// BAD: O(n^2) - includes() is O(n), called n times
|
|
673
|
+
function removeDuplicates(arr) {
|
|
674
|
+
const result = [];
|
|
675
|
+
for (const item of arr) {
|
|
676
|
+
if (!result.includes(item)) {
|
|
677
|
+
result.push(item);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**Why developers do it:**
|
|
685
|
+
The naive solution is the first one that comes to mind and is the easiest to write. With small inputs during development (n=100), O(n^2) completes in microseconds. Developers may not recognize that array methods like `includes`, `indexOf`, and `filter` are O(n) operations that create quadratic behavior when called inside loops.
|
|
686
|
+
|
|
687
|
+
**What goes wrong:**
|
|
688
|
+
A University of Chicago research paper on performance diagnosis for inefficient loops documented that such performance bugs "widely exist in deployed software" and waste energy during production runs. With n=1,000, O(n^2) performs 1,000,000 operations -- noticeable but tolerable. With n=100,000 (common in production), O(n^2) performs 10 billion operations, taking minutes instead of milliseconds. The jump from "works fine" to "completely broken" happens abruptly as data grows, with no gradual warning.
|
|
689
|
+
|
|
690
|
+
**The fix:**
|
|
691
|
+
Use hash-based data structures (Set, Map, dictionary) for O(1) lookups. Know your standard library's time complexities. Use sorting + binary search when hash maps aren't suitable:
|
|
692
|
+
|
|
693
|
+
```javascript
|
|
694
|
+
// GOOD: O(n) using Set
|
|
695
|
+
function removeDuplicates(arr) {
|
|
696
|
+
return [...new Set(arr)];
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// GOOD: O(n) using Map for lookups in loops
|
|
700
|
+
const lookup = new Map(items.map(item => [item.id, item]));
|
|
701
|
+
for (const ref of references) {
|
|
702
|
+
const item = lookup.get(ref.itemId); // O(1) instead of O(n)
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
**Detection rule:**
|
|
707
|
+
If an array search method (includes, indexOf, find, filter) is called inside a loop iterating over a collection of similar size, this is AP-16. If execution time grows noticeably when input doubles, profile for quadratic behavior.
|
|
708
|
+
|
|
709
|
+
---
|
|
710
|
+
|
|
711
|
+
### AP-17: Synchronous Serialization/Deserialization
|
|
712
|
+
|
|
713
|
+
**Also known as:** JSON.parse Everything, Blocking Serialization, Payload Processing Bottleneck
|
|
714
|
+
**Frequency:** Common
|
|
715
|
+
**Severity:** Medium
|
|
716
|
+
**Detection difficulty:** Moderate
|
|
717
|
+
|
|
718
|
+
**What it looks like:**
|
|
719
|
+
Large payloads are serialized or deserialized synchronously on the main thread, or data is repeatedly serialized/deserialized unnecessarily:
|
|
720
|
+
|
|
721
|
+
```javascript
|
|
722
|
+
// BAD: parsing a 10MB JSON response on the main thread
|
|
723
|
+
const data = JSON.parse(hugeJsonString); // blocks for 200ms+
|
|
724
|
+
|
|
725
|
+
// BAD: unnecessary round-trip through JSON for deep cloning
|
|
726
|
+
const copy = JSON.parse(JSON.stringify(complexObject));
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
**Why developers do it:**
|
|
730
|
+
`JSON.parse` and `JSON.stringify` are the simplest way to work with JSON data and create deep copies. They appear in every tutorial. The performance cost is invisible with small payloads. `JSON.parse(JSON.stringify(obj))` is the most commonly recommended deep clone technique despite being extremely slow.
|
|
731
|
+
|
|
732
|
+
**What goes wrong:**
|
|
733
|
+
For large payloads (1MB+), JSON.parse can block the main thread for hundreds of milliseconds, causing visible UI freezes in browsers or event loop lag in Node.js. The JSON.parse/stringify deep clone pattern is particularly expensive: it serializes to string (allocating memory for the string representation), then parses back (allocating all new objects) -- performing double the work of a proper deep clone. With deeply nested objects, this can take 10-100x longer than structural cloning. When used in loops or hot paths, the compound effect is devastating.
|
|
734
|
+
|
|
735
|
+
**The fix:**
|
|
736
|
+
Use `structuredClone()` (available in modern runtimes) for deep cloning. Use streaming JSON parsers for large payloads. Move heavy parsing to Web Workers or worker threads. Avoid unnecessary serialization round-trips:
|
|
737
|
+
|
|
738
|
+
```javascript
|
|
739
|
+
// GOOD: native structured clone (3-10x faster than JSON round-trip)
|
|
740
|
+
const copy = structuredClone(complexObject);
|
|
741
|
+
|
|
742
|
+
// GOOD: streaming parser for large JSON
|
|
743
|
+
const stream = new ReadableStream(/* ... */);
|
|
744
|
+
const data = await parseJsonStream(stream);
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
**Detection rule:**
|
|
748
|
+
If `JSON.parse(JSON.stringify(obj))` appears anywhere, this is AP-17. If JSON.parse is called on payloads that could exceed 100KB, suspect AP-17 on the main thread.
|
|
749
|
+
|
|
750
|
+
---
|
|
751
|
+
|
|
752
|
+
### AP-18: Unnecessary Deep Copies
|
|
753
|
+
|
|
754
|
+
**Also known as:** Clone Everything, Defensive Copying Overkill, Immutability Tax
|
|
755
|
+
**Frequency:** Common
|
|
756
|
+
**Severity:** Medium
|
|
757
|
+
**Detection difficulty:** Moderate
|
|
758
|
+
|
|
759
|
+
**What it looks like:**
|
|
760
|
+
Code deep-clones entire object graphs when only a shallow copy or no copy is needed:
|
|
761
|
+
|
|
762
|
+
```javascript
|
|
763
|
+
// BAD: deep clone just to change one field
|
|
764
|
+
const updated = JSON.parse(JSON.stringify(user));
|
|
765
|
+
updated.name = 'New Name';
|
|
766
|
+
|
|
767
|
+
// BAD: deep clone on every state update in a loop
|
|
768
|
+
items.forEach(item => {
|
|
769
|
+
const state = cloneDeep(entireAppState);
|
|
770
|
+
state.items[item.id] = item;
|
|
771
|
+
setState(state);
|
|
772
|
+
});
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
**Why developers do it:**
|
|
776
|
+
Immutability is a best practice in React and Redux ecosystems. Developers internalize "never mutate state" and apply deep cloning as a blanket solution. `lodash.cloneDeep` and the JSON round-trip are easy to reach for. The performance cost is invisible with small state objects.
|
|
777
|
+
|
|
778
|
+
**What goes wrong:**
|
|
779
|
+
Deep cloning creates entirely new copies of all nested objects, consuming time proportional to the full object graph size. With large state trees (common in data-heavy applications), deep cloning on every update can consume 50%+ of the JavaScript frame budget. In memory-constrained mobile environments, the duplicate objects double memory pressure and trigger garbage collection pauses. When done in loops, the cost multiplies per iteration.
|
|
780
|
+
|
|
781
|
+
**The fix:**
|
|
782
|
+
Use shallow copies with spread syntax for top-level changes. Use structural sharing (Immer, Immutable.js) for nested updates. Only clone the path that changes:
|
|
783
|
+
|
|
784
|
+
```javascript
|
|
785
|
+
// GOOD: shallow copy + targeted update
|
|
786
|
+
const updated = { ...user, name: 'New Name' };
|
|
787
|
+
|
|
788
|
+
// GOOD: Immer - structural sharing, only changed paths are cloned
|
|
789
|
+
import produce from 'immer';
|
|
790
|
+
const nextState = produce(state, draft => {
|
|
791
|
+
draft.items[itemId] = newItem;
|
|
792
|
+
});
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
**Detection rule:**
|
|
796
|
+
If `cloneDeep`, `structuredClone`, or `JSON.parse(JSON.stringify())` is called on objects where only 1-2 fields are changing, this is AP-18. If deep cloning appears inside loops or event handlers that fire frequently, suspect AP-18.
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
### AP-19: Excessive DOM Manipulation
|
|
801
|
+
|
|
802
|
+
**Also known as:** Death by a Thousand Appends, Direct DOM Surgery
|
|
803
|
+
**Frequency:** Common
|
|
804
|
+
**Severity:** Medium
|
|
805
|
+
**Detection difficulty:** Moderate
|
|
806
|
+
|
|
807
|
+
**What it looks like:**
|
|
808
|
+
Code makes many individual DOM modifications instead of batching them, triggering repeated reflows and repaints:
|
|
809
|
+
|
|
810
|
+
```javascript
|
|
811
|
+
// BAD: 1000 individual DOM mutations
|
|
812
|
+
for (let i = 0; i < 1000; i++) {
|
|
813
|
+
const li = document.createElement('li');
|
|
814
|
+
li.textContent = `Item ${i}`;
|
|
815
|
+
list.appendChild(li); // triggers layout on each append
|
|
816
|
+
}
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
**Why developers do it:**
|
|
820
|
+
DOM manipulation APIs are imperative and work one element at a time. The pattern of "create element, append to parent" is taught in every beginner tutorial. Without framework abstractions (React's virtual DOM, Vue's reactivity), developers default to direct manipulation.
|
|
821
|
+
|
|
822
|
+
**What goes wrong:**
|
|
823
|
+
Each `appendChild` can trigger a reflow if the parent is in the document. With 1,000 appends, the browser potentially recalculates layout 1,000 times. Google's web.dev documentation shows this causes dropped frames, visual jank during list rendering, and unnecessarily high CPU usage. On mobile devices, this directly impacts battery life due to GPU and CPU wake-ups for each paint cycle.
|
|
824
|
+
|
|
825
|
+
**The fix:**
|
|
826
|
+
Use `DocumentFragment` for batch DOM insertions. Use `innerHTML` for large HTML blocks. Better yet, use a framework's virtual DOM:
|
|
827
|
+
|
|
828
|
+
```javascript
|
|
829
|
+
// GOOD: batch with DocumentFragment
|
|
830
|
+
const fragment = document.createDocumentFragment();
|
|
831
|
+
for (let i = 0; i < 1000; i++) {
|
|
832
|
+
const li = document.createElement('li');
|
|
833
|
+
li.textContent = `Item ${i}`;
|
|
834
|
+
fragment.appendChild(li);
|
|
835
|
+
}
|
|
836
|
+
list.appendChild(fragment); // single reflow
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
**Detection rule:**
|
|
840
|
+
If DOM insertion methods (appendChild, insertBefore, innerHTML assignment) appear inside a loop with >10 iterations on elements already in the document, this is AP-19.
|
|
841
|
+
|
|
842
|
+
---
|
|
843
|
+
|
|
844
|
+
### AP-20: String Concatenation in Loops
|
|
845
|
+
|
|
846
|
+
**Also known as:** The Quadratic String, StringBuilder Ignorance
|
|
847
|
+
**Frequency:** Common
|
|
848
|
+
**Severity:** Medium
|
|
849
|
+
**Detection difficulty:** Easy
|
|
850
|
+
|
|
851
|
+
**What it looks like:**
|
|
852
|
+
Building a string by concatenating with `+` or `+=` inside a loop, creating a new string object on each iteration:
|
|
853
|
+
|
|
854
|
+
```java
|
|
855
|
+
// BAD: O(n^2) time - new string allocated each iteration
|
|
856
|
+
String result = "";
|
|
857
|
+
for (String item : items) {
|
|
858
|
+
result += item + ","; // copies entire string on each iteration
|
|
859
|
+
}
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
**Why developers do it:**
|
|
863
|
+
String concatenation with `+` is the most intuitive string building pattern. It's taught first in every language tutorial. With small inputs, performance is indistinguishable from StringBuilder. Developers may not understand that strings are immutable in Java, C#, Python, and Go.
|
|
864
|
+
|
|
865
|
+
**What goes wrong:**
|
|
866
|
+
JetBrains IntelliJ explicitly flags this pattern. Because strings are immutable, each `+=` allocates a new string and copies all previous content. Concatenating n strings of equal length takes O(n^2) time. Redfin Engineering benchmarked Java string building: concatenating 100,000 strings with `+` takes 4,970ms vs. 1.5ms with StringBuilder -- a 3,300x difference. The compiler may optimize single-statement concatenation, but inside loops, a new StringBuilder is created per iteration, negating the optimization.
|
|
867
|
+
|
|
868
|
+
**The fix:**
|
|
869
|
+
Use language-specific builders for loop-based string construction:
|
|
870
|
+
|
|
871
|
+
```java
|
|
872
|
+
// GOOD: O(n) time
|
|
873
|
+
StringBuilder sb = new StringBuilder();
|
|
874
|
+
for (String item : items) {
|
|
875
|
+
sb.append(item).append(",");
|
|
876
|
+
}
|
|
877
|
+
String result = sb.toString();
|
|
878
|
+
```
|
|
879
|
+
|
|
880
|
+
```python
|
|
881
|
+
# GOOD: join is O(n)
|
|
882
|
+
result = ",".join(items)
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
```javascript
|
|
886
|
+
// GOOD: array join in JavaScript
|
|
887
|
+
const result = items.join(",");
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Note: In JavaScript, modern engines optimize string concatenation well, so this is primarily a concern in Java, C#, Python, and Go.
|
|
891
|
+
|
|
892
|
+
**Detection rule:**
|
|
893
|
+
If string concatenation (`+=` or `+`) appears inside a loop body in Java, C#, Python, or Go, this is AP-20. Less critical in JavaScript/Ruby due to engine optimizations.
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
### AP-21: Loading Everything Upfront
|
|
898
|
+
|
|
899
|
+
**Also known as:** No Lazy Loading, Eager Everything, The Blank Screen
|
|
900
|
+
**Frequency:** Very Common
|
|
901
|
+
**Severity:** Medium
|
|
902
|
+
**Detection difficulty:** Easy
|
|
903
|
+
|
|
904
|
+
**What it looks like:**
|
|
905
|
+
The application loads all resources, data, and components at startup regardless of whether the user will need them:
|
|
906
|
+
|
|
907
|
+
```javascript
|
|
908
|
+
// BAD: load all translations, all feature modules, all data at startup
|
|
909
|
+
import allTranslations from './i18n/all-languages';
|
|
910
|
+
import adminModule from './modules/admin';
|
|
911
|
+
import analyticsModule from './modules/analytics';
|
|
912
|
+
const allData = await fetch('/api/everything');
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
**Why developers do it:**
|
|
916
|
+
Loading everything at startup makes the application simpler: no loading states, no error handling for lazy loads, no code splitting boundaries to design. The experience feels snappy after the initial load. "Preloading" sounds like an optimization. Developers test on fast connections where the upfront cost is negligible.
|
|
917
|
+
|
|
918
|
+
**What goes wrong:**
|
|
919
|
+
The initial page load becomes the bottleneck. Users see a blank screen or loading spinner for seconds while the application downloads resources they may never use. On mobile networks (average 1.6 Mbps for 3G), loading 5MB of JavaScript + 2MB of images means 30+ seconds before anything is interactive. Google's web.dev recommends code splitting specifically because most users only interact with 10-20% of an application's features per session. Loading the admin dashboard for non-admin users wastes bandwidth and delays time-to-interactive for everyone.
|
|
920
|
+
|
|
921
|
+
**The fix:**
|
|
922
|
+
Use lazy loading for routes, images, and heavy components. Load data on demand. Use `IntersectionObserver` for lazy-loading below-fold content:
|
|
923
|
+
|
|
924
|
+
```javascript
|
|
925
|
+
// GOOD: lazy-load routes
|
|
926
|
+
const Admin = React.lazy(() => import('./modules/admin'));
|
|
927
|
+
const Analytics = React.lazy(() => import('./modules/analytics'));
|
|
928
|
+
|
|
929
|
+
// GOOD: lazy-load images below the fold
|
|
930
|
+
<img src="hero.webp" loading="lazy" />
|
|
931
|
+
|
|
932
|
+
// GOOD: fetch data when needed
|
|
933
|
+
useEffect(() => { if (activeTab === 'analytics') loadAnalytics(); }, [activeTab]);
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
**Detection rule:**
|
|
937
|
+
If all routes/features are statically imported at the entry point, this is AP-21. If API calls at startup fetch data for features not visible on the initial screen, suspect AP-21.
|
|
938
|
+
|
|
939
|
+
---
|
|
940
|
+
|
|
941
|
+
## Root Cause Analysis
|
|
942
|
+
|
|
943
|
+
| Anti-Pattern | Root Cause | Prevention |
|
|
944
|
+
|-------------|------------|------------|
|
|
945
|
+
| AP-01: N+1 Query | **Ignorance** -- ORM hides query generation | Enable query logging in development; use N+1 detection tools (bullet, django-query-count) |
|
|
946
|
+
| AP-02: Missing Indexes | **Ignorance** -- small dev data masks the problem | Mandate EXPLAIN ANALYZE in code review for new queries; monitor slow query logs |
|
|
947
|
+
| AP-03: Memory Leaks | **Ignorance** -- GC creates false safety | Pair every resource acquisition with cleanup; monitor production memory trends |
|
|
948
|
+
| AP-04: Blocking Main Thread | **Laziness** -- sync code is simpler to write | Use StrictMode (Android), lint rules for sync I/O, event loop lag monitoring |
|
|
949
|
+
| AP-05: Layout Thrashing | **Ignorance** -- DOM reads look cheap | Batch reads before writes; use FastDOM; profile with Chrome DevTools |
|
|
950
|
+
| AP-06: Unoptimized Images | **Laziness** -- optimization is a "later" task | Add image optimization to build pipeline; set size budgets in CI |
|
|
951
|
+
| AP-07: No Pagination | **Laziness** -- rendering everything is simpler | Design for production data volumes from the start; require limit/offset on all list endpoints |
|
|
952
|
+
| AP-08: Unnecessary Re-renders | **Ignorance** -- new references defeat memoization | Use React DevTools Profiler; stabilize references with useMemo/useCallback |
|
|
953
|
+
| AP-09: Large Bundles | **Cargo culting** -- adding dependencies without checking size | Set bundle size budgets; require size impact review for new dependencies |
|
|
954
|
+
| AP-10: No Connection Pooling | **Copy-paste from tutorials** -- examples show single connections | Use framework-provided pool management; never instantiate connections in handlers |
|
|
955
|
+
| AP-11: Excessive Network Requests | **Ignorance** -- individual requests feel simple | Monitor request count per page load; batch by default |
|
|
956
|
+
| AP-12: Logging in Hot Paths | **Laziness** -- debug logs not removed after debugging | Lint for log statements in loops; set production log level to INFO minimum |
|
|
957
|
+
| AP-13: Over-Fetching | **Laziness** -- SELECT * is easier to write | Ban SELECT *; require explicit field lists in queries and API designs |
|
|
958
|
+
| AP-14: Polling vs Push | **Laziness** -- polling requires no server changes | Evaluate update frequency requirements early; use SSE for simple push |
|
|
959
|
+
| AP-15: No CDN | **Ignorance** -- latency invisible to co-located developers | Add CDN as a standard infrastructure component; test from multiple geographies |
|
|
960
|
+
| AP-16: Quadratic Algorithms | **Ignorance** -- O(n) methods hidden inside O(n) loops | Know time complexity of standard library methods; profile with scaled inputs |
|
|
961
|
+
| AP-17: Sync Serialization | **Cargo culting** -- JSON.parse/stringify is the default copy pattern | Use structuredClone; stream large payloads; move parsing off main thread |
|
|
962
|
+
| AP-18: Unnecessary Deep Copies | **Cargo culting** -- "immutability" applied without understanding | Use shallow copies for top-level changes; adopt Immer for nested updates |
|
|
963
|
+
| AP-19: Excessive DOM Manipulation | **Ignorance** -- DOM APIs are imperative by nature | Use DocumentFragment; prefer frameworks with virtual DOM |
|
|
964
|
+
| AP-20: String Concat in Loops | **Ignorance** -- string immutability not understood | Use StringBuilder (Java/C#), join() (Python/JS); linters flag this pattern |
|
|
965
|
+
| AP-21: Loading Everything Upfront | **Laziness** -- no lazy loading means no loading states to handle | Make lazy loading the default; audit initial bundle with coverage tools |
|
|
966
|
+
|
|
967
|
+
## Self-Check Questions
|
|
968
|
+
|
|
969
|
+
1. How many database queries does this page/endpoint execute? Could any of them be combined or eliminated?
|
|
970
|
+
2. Have I run EXPLAIN ANALYZE on this query with production-scale data volumes?
|
|
971
|
+
3. Does this component/handler clean up every resource it acquires (listeners, timers, connections, subscriptions)?
|
|
972
|
+
4. Is there any I/O (network, disk, database) happening synchronously on the main/UI thread?
|
|
973
|
+
5. Am I reading and writing DOM layout properties in the same loop iteration?
|
|
974
|
+
6. Are my images optimized for the web (format, compression, responsive sizing, lazy loading)?
|
|
975
|
+
7. How many items could this list contain in production? Do I need pagination or virtual scrolling?
|
|
976
|
+
8. Will this component re-render unnecessarily because I'm creating new object/function references inline?
|
|
977
|
+
9. What is the total size of my JavaScript bundle? Have I code-split by route?
|
|
978
|
+
10. Am I creating a new database/HTTP connection for every request instead of using a pool?
|
|
979
|
+
11. How many network requests does this user interaction trigger? Can any be batched or cached?
|
|
980
|
+
12. Is there logging inside this loop or hot path that will run thousands of times per second?
|
|
981
|
+
13. Am I fetching more data than I actually use from this query or API call?
|
|
982
|
+
14. Am I polling for data that the server could push to me?
|
|
983
|
+
15. What is the time complexity of this algorithm? Does it contain hidden quadratic behavior (O(n) methods inside O(n) loops)?
|
|
984
|
+
|
|
985
|
+
## Code Smell Quick Reference
|
|
986
|
+
|
|
987
|
+
| If you see... | Suspect... | Verify... |
|
|
988
|
+
|---------------|-----------|-----------|
|
|
989
|
+
| Database query inside a `for`/`forEach` loop | AP-01: N+1 Query | Check if the loop iterates over results of another query |
|
|
990
|
+
| `SELECT *` in SQL or ORM equivalent | AP-02/AP-13: Missing Index / Over-Fetching | Run EXPLAIN; check if all columns are used |
|
|
991
|
+
| `addEventListener` without corresponding `removeEventListener` | AP-03: Memory Leak | Check component cleanup/unmount lifecycle |
|
|
992
|
+
| `readFileSync`, synchronous HTTP, or heavy computation on main thread | AP-04: Blocking Main Thread | Profile event loop lag or UI responsiveness |
|
|
993
|
+
| `el.offsetHeight` followed by `el.style.height =` in a loop | AP-05: Layout Thrashing | Separate reads and writes into distinct passes |
|
|
994
|
+
| Image files >500KB or `<img>` without `loading="lazy"` | AP-06: Unoptimized Images | Check format, compression, and responsive sizing |
|
|
995
|
+
| `.map()` rendering list with no `limit` and data source can grow | AP-07: No Pagination | Check maximum possible list size in production |
|
|
996
|
+
| Inline `() =>` or `{{ }}` object literals in JSX props | AP-08: Unnecessary Re-renders | Check if child component uses React.memo |
|
|
997
|
+
| `import` of full library when one function is needed | AP-09: Large Bundle | Run bundle analyzer; check tree-shaking |
|
|
998
|
+
| `new Connection()` or `createConnection()` in a request handler | AP-10: No Connection Pooling | Check if a pool is configured and connections are returned |
|
|
999
|
+
| Multiple `fetch()` calls to same API with different IDs | AP-11: Excessive Requests | Check if a batch endpoint exists or could be created |
|
|
1000
|
+
| `console.log` or `logger.debug` inside a loop | AP-12: Logging in Hot Paths | Check if this code runs >100x/second in production |
|
|
1001
|
+
| API response JSON significantly larger than data rendered | AP-13: Over-Fetching | Compare response payload to fields actually used |
|
|
1002
|
+
| `setInterval` + `fetch` | AP-14: Polling | Check if the server supports WebSocket or SSE |
|
|
1003
|
+
| Static files served from same origin as API, no cache headers | AP-15: No CDN | Check response headers for CDN indicators |
|
|
1004
|
+
| `array.includes()` or `array.find()` inside a loop | AP-16: Quadratic Algorithm | Convert to Set or Map for O(1) lookups |
|
|
1005
|
+
| `JSON.parse(JSON.stringify(obj))` | AP-17/AP-18: Sync Serialization / Unnecessary Clone | Use structuredClone or shallow copy if sufficient |
|
|
1006
|
+
| `cloneDeep()` when only 1-2 fields change | AP-18: Unnecessary Deep Copy | Use spread operator or Immer |
|
|
1007
|
+
| `appendChild()` inside a loop on a live DOM node | AP-19: Excessive DOM Manipulation | Use DocumentFragment or virtual DOM |
|
|
1008
|
+
| `string += value` inside a loop (Java, C#, Python) | AP-20: String Concatenation | Use StringBuilder or join() |
|
|
1009
|
+
| All route components imported statically at entry point | AP-21: No Lazy Loading | Use dynamic imports / React.lazy |
|
|
1010
|
+
|
|
1011
|
+
---
|
|
1012
|
+
|
|
1013
|
+
*Researched: 2026-03-08 | Sources: [PlanetScale: N+1 Query Problem](https://planetscale.com/blog/what-is-n-1-query-problem-and-how-to-solve-it), [Sentry: N+1 Queries](https://docs.sentry.io/product/issues/issue-details/performance-issues/n-one-queries/), [Sentry: Missing Indexes](https://blog.sentry.io/missing-indexes-are-slowing-down-your-database-heres-how-to-find-and-fix/), [Cloudflare: Cloudbleed Incident Report](https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/), [Elastic: Memory Leak Post-Mortem](https://www.elastic.co/blog/postmortem-memory-leak-hunting-windows), [Ayende: RavenDB Memory Leak](https://ayende.com/blog/195681-B/production-postmortem-the-memory-leak-that-only-happened-on-linux), [Node.js: Don't Block the Event Loop](https://nodejs.org/en/learn/asynchronous-work/dont-block-the-event-loop), [Trigger.dev: Event Loop Lag](https://trigger.dev/blog/event-loop-lag), [Ashby: Detecting Event Loop Blockers](https://www.ashbyhq.com/blog/engineering/detecting-event-loop-blockers), [Paul Irish: What Forces Layout](https://gist.github.com/paulirish/5d52fb081b3570c81e3a), [Google web.dev: Layout Thrashing](https://web.dev/articles/avoid-large-complex-layouts-and-layout-thrashing), [MDN: Fix Image LCP](https://developer.mozilla.org/en-US/blog/fix-image-lcp/), [Google web.dev: Code Splitting](https://web.dev/articles/reduce-javascript-payloads-with-code-splitting), [Smashing Magazine: Bundle Performance](https://www.smashingmagazine.com/2022/02/javascript-bundle-performance-code-splitting/), [DebugBear: React Rerenders](https://www.debugbear.com/blog/react-rerenders), [Stack Overflow: Connection Pooling](https://stackoverflow.blog/2020/10/14/improve-database-performance-with-connection-pooling/), [dotnet/aspnetcore#18089: Connection Pool Exhaustion](https://github.com/dotnet/aspnetcore/issues/18089), [Ably: WebSockets vs Long Polling](https://ably.com/blog/websockets-vs-long-polling), [Cloudflare: CDN Performance](https://www.cloudflare.com/learning/cdn/performance/), [Sivachandran: Logging in Hot Paths](https://www.sivachandran.in/2021/03/logging-overhead-in-hot-code-path.html), [Redfin: Java String Concatenation](https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8), [JetBrains: String Concatenation in Loop](https://www.jetbrains.com/help/inspectopedia/StringContatenationInLoop.html), [Nordic APIs: Overfetching](https://nordicapis.com/how-to-avoid-overfetching-and-underfetching/), [ACM Queue: Performance Anti-Patterns](https://queue.acm.org/detail.cfm?id=1117403), [Microsoft Azure: Performance Antipatterns](https://learn.microsoft.com/en-us/azure/architecture/antipatterns/), [Android Developers: ANRs](https://developer.android.com/topic/performance/vitals/anr), [UChicago: Performance Diagnosis for Inefficient Loops](https://people.cs.uchicago.edu/~shanlu/paper/ICSE-TR-105.pdf)*
|