Bitrix code review: where the design diverges from the production environment
The project design is almost always cleaner than the production environment.
In the documentation, the core is separated from templates, event handlers reside in a module, and changes go through versioning — on the production server, some edits were made directly in the template, some through the admin panel, and some by a script connecting to the database.
That is why Bitrix code review starts not with reading the policy, but with verification: what actually runs in the production environment and how it differs from the described architecture.
The first thing that surfaces during a code audit is duplication and overlapping. Three handlers registered at different times intercept the same event, and no one has checked the order in which they fire.
Alongside are manual operations: editing a property directly in the interface, triggering recalculation manually, updating a module without running it on a copy. Such actions are not reproduced on a test environment, and any enhancement turns into an analysis of consequences.
Performance bottlenecks are almost never related to “bad” hosting. They are queries inside a loop over elements, a cache that resets on every change, agents hanging in the schedule for years, and indexes missing for actual queries.
A project’s technical debt is measured not by the volume of code, but by the cost of the next change: how many files must be touched to change one field, and how many manual steps are built into it.
Due to the absence of an update policy, edits accumulate in layers, and after several releases no one ventures to say which version of the core and modules is assembled in the production environment. We examine how this can be resolved.
The effect of an audit: response speed, release stability
A performance audit ends not with a report, but with a checklist with before and after figures: median site response time under load, number of database calls per page, cache hits, interface build time.
The list is closed by repeated measurement on the same environment and the same scenarios — otherwise there is nothing to compare.
| Failure class | What is visible in the code | What changes after edits |
|---|---|---|
| Degradation under load | Queries in a loop, component cache not enabled, queries without a limit | Response time stops growing with the number of concurrent visitors |
| Intermittent failures | No timeouts or handling of external calls, errors are suppressed | The page returns a response or a clear error instead of a blank screen |
| Breaking updates | Edits in the core, manual template patches, custom library versions | The update is installed on a copy, rollback returns the previous state |
| Permission sprawl | Logic in the template, duplication, no checks | A change is covered by a test suite, release proceeds predictably |
Release stability rests on the same code: if edits do not touch the core and are covered by checks, release stops being a risky operation. We work with 1C-Bitrix and know where the platform suggests a ready-made solution and where we have to design it ourselves.
Bitrix code review formats: one-time audit or regular control
The format of work is chosen based on the state of the codebase and the frequency of changes, not the size of the site. If enhancements occur once a quarter and a large block of edits accumulates before a release, a one-time audit is sufficient.
When releases are weekly and several people work on the code, a one-time review report becomes outdated faster than it gets into work — here a code review policy on an ongoing basis is needed.
The critical contour — authorization, payments, access rights, exchange with 1C — is checked in a separate stream regardless of the chosen format.
| Format | When it fits | Limitations |
|---|---|---|
| One-time audit | Before a major change, migration, or after a contractor change | Snapshot as of a date: edits after the review are not covered |
| Regular code control | Continuous releases, several developers in one branch | Requires an agreed policy and time for review in each cycle |
| Critical contour audit | Payments, authorization, access rights, exchange with 1C | Does not cover the rest of the codebase — debt remains in standard modules |
| Legacy review | Long history of edits, no up-to-date documentation | Shows debt but does not eliminate it — a work plan is needed |
The formats are not mutually exclusive: a one-time review sets the plan, regular control keeps it on track, and a critical contour audit covers the areas where the cost of a missed error is highest.
Work order: from code inventory to policies
Code review produces results only if it follows a fixed sequence: first code inventory, then a dependency map, and only then edits.
The reverse order turns code review into a list of findings without priorities — fixing one module breaks a neighboring one, and the cause of degradation remains unfound.
- Code inventory. We traverse the project tree and record everything written by hand: custom modules and components, overridden templates, event handlers, background jobs, exchange scripts. We separate custom code from standard code — this immediately shows what share of the project lives outside core updates.
- Dependency map. We build connections between modules, components, and external services: who calls whom, where logic is duplicated, where there is one entry point and where there are five. The map determines the blast radius — without it, any edit is risky.
- Review of critical modules. Authorization and access rights, payments, exchange with the accounting system, exports and imports come first. We look at database queries, cache operation, error handling, and external calls.
- Check on a test environment. We deploy a copy of the project and reproduce the problem before the edit: if the behavior does not recur, then the cause is not where it seemed.
- Remediation of findings. We release edits in small portions, each can be rolled back separately — this way an incident does not block the rest of the plan.
- Acceptance of work. Repeat run of scenarios and comparison of measurements before and after: response time, number of errors, share of pages under cache.
- Handover of policies. Developers receive rules for updates, cache operation, and template edits — so the state does not roll back in a couple of months.
The outcome of this stage is not a list of findings, but a code map, priorities, and working agreements according to which the client’s team continues work independently.
Case study: how we eliminated regression during module updates
The client is an online store on 1C-Bitrix with a history of edits in standard modules: order placement and delivery calculation were customized directly in the component code.
Security updates were released regularly, and almost every other one broke the checkout scenario — product offers disappeared from the cart, and the error was discovered only from customer calls.
Rollback to the previous build took half a workday: we brought up a copy, transferred the edits again, and manually verified templates.
The code audit showed that the customizations were mixed with standard code, so any update overwrote the logic.
We moved calculations and checkout rules into custom modules and overrides, leaving standard files untouched, and fixed the exchange contracts with the accounting system.
Three key scenarios — order placement, cart recalculation, order export — were covered by automated checks that run before release deployment.
Before and after metrics: the share of paths covered by automated tests grew from about 10% to 85%, and the run itself takes minutes and does not require a manual checklist.
The update is now first installed on a copy, passes checks, and is transferred to production in one pass — about 40 minutes instead of six hours.
Over six months of observation — not a single rollback and not a single outage after an update.
If a release does not pass checks, we roll back to the previous build in minutes: recovery after failure stopped being a separate operation with manual merging of edits and became a standard button in the policy.
How does a security audit differ from a performance audit?
Both reviews go through the same code, but with different goals. A security audit looks for ways to bypass controls: where data comes from the user without validation, where permissions are granted more broadly than necessary, what is generally accessible from outside.
A performance audit calculates the cost of request processing: how much work the system does to serve a page, and what of that work can be avoided entirely.
A security audit starts with the boundaries: server configuration, file and database account permissions, availability of backups, logs, and the admin panel.
Then comes the code — handling forms and uploaded files, working with sessions and tokens, output escaping, separation of user group permissions, and the currency of modules and third-party libraries. The output is reproducible scenarios with severity ratings, not a general list of findings.
A performance audit is built on measurements: page delivery time, number of queries per page, repeated queries inside loops, missing indexes, cache layers and reset frequency, background tasks triggered on every request.
First, a picture is captured on production traffic, then the most expensive parts are fixed — as a rule, these are several templates and components that create the main load.
The directions intersect in configuration: a cache serving personal data to the wrong user, a database account with excessive permissions, debug mode enabled on the production server.
Therefore, the order of checks on a live project is as follows: inventory, then security — critical items are closed immediately — and only after that performance. Speeding up an open node is pointless: the load is the same, only it is more convenient for an attacker.
What to choose: if there were incidents or suspicions — start with security; if there are complaints about speed — start with performance; after major changes, both directions are checked in one pass through 1C-Bitrix.
Technical concerns about code review and access
A code audit almost never starts on an empty project: traffic is flowing, exchanges with 1C are running, releases are coming out.
Therefore, we structure the review so that it does not interfere with production — we read the repository, change history, and environment configuration, and run performance measurements on a database copy.
The project cannot be stopped — how can the review be combined with ongoing work?
We do not touch production: we raise a test environment from a code copy and database snapshot, and perform checks on it. We divide findings by severity — from vulnerabilities to style issues — so that edits go in portions and do not break the release cycle.
Can only part be checked — for example, payment or exchange with 1C?
Yes. We agree on the boundaries in advance: a module, component, or specific scenario. Such a review shows local problems and bottlenecks, but does not replace a full architecture assessment — we state this directly in the conclusions.
How are access credentials transferred and how are they revoked?
Read permissions to the repository and access to a database copy are sufficient; production settings and personal data are not required. We work from a separate account — you revoke it with one operation; the procedure and timeframe are fixed before the start.
What to do about core updates and edits in the core?
We mark modified core and component files: after an update, such edits are lost or conflict. We propose moving customizations into custom modules and templates so that updates can again be installed routinely and predictably.
Let’s discuss the task and come back with a work plan
To discuss the task substantively and come back with a timeline estimate rather than general wording, a minimum is enough for us: read access to the repository, a test environment or project copy where the problem is reproduced, and a description of symptoms — which pages return an error, where response time grows, which admin sections are slow.
If change history is maintained, send the branch with the latest edits: it shows at what point the degradation appeared, and this noticeably shortens the review.
To start, we need from you:
- a list of sites and environments included in the task;
- access to the repository and test environment, or a code copy;
- a description of symptoms and when they appeared;
- priority: security, performance, or architecture;
- constraints — what cannot be changed and what has already been tried;
- contact of the engineer who will answer clarifying questions.
The work plan comes as a document: identified bottlenecks tied to files and modules, stages, timelines for each stage, and points where we show an interim result.
The procedure for handing over the result upon completion follows the same principle of transparency: modified code with explanations, an edit report, an update policy, instructions for your developers, and a protocol of re-checking on the original scenarios. Describe the task — we will come back with an estimate and a plan.

