Job legacy-extract-one-module-behind-interface · revised 11 October 2026
Pull one self-contained module out of a monolith behind a tested interface
One module of a monolith gets a documented interface that every caller uses, a contract test passing on the current code and on a separate copy, and a switch that selects which answers.
You might be seeing
- Changes to one area need a full-application release and a full regression run
- Other code reaches into the module's internals and tables, so nobody can change it safely
- An earlier attempt to split the application stalled because the boundary was never defined
No passwords, keys, card details or admin invites needed to start.
What usually happened
A module inside a monolith is rarely as separate as its folder suggests. Other code calls its internal functions directly, reads its database tables and relies on shared state, so moving it out breaks callers nobody knew about. Extracting the module in one move, as a new service with a new database, replaces an invisible dependency with a network call and a data-ownership problem at the same time. The safer first move is to make the boundary real inside the monolith, prove it with tests, and only then run the module separately.
Who it’s for: An engineering lead whose monolith has one part that changes often, scales differently or needs a different runtime, and who wants to separate that part without rewriting the rest.
Usually starts when: One module forces the whole application to be released together, a team wants to own a part independently, or a part needs a newer runtime than the rest of the code can use.
The result: One agreed module is reachable only through a documented interface. A contract test suite passes against the module in its current place and against a separately running copy, a configuration switch chooses which one answers, and no code outside the module reads its internals or writes its tables.
Check whether this job fits
Five short questions. Your answers stay on this page unless you choose to email them.
Checks you can run yourself
Count the places that use the module
Ask a developer to run this read-only search in a copy of the project folder, replacing the module name and the module's folder name, and send the number. It skips installed dependencies and the module's own folder.
grep -rn "YOUR_MODULE_NAME" --include='*.rb' --include='*.py' --include='*.php' --include='*.js' --include='*.ts' --exclude-dir=node_modules --exclude-dir=vendor --exclude-dir=YOUR_MODULE_FOLDER . | wc -lLook for: A count of references outside the module itself. The fixed scope covers up to 40 call sites.
List the database tables the module touches
Ask a developer to search the module's code for table names and send the list, not the code.
Look for: Table names. Then search the rest of the code for the same names: any hit is an access to be routed through the interface.
What you get
- The interface description and the contract test suite
- The changed callers and the separately running module as pull requests
- A map of what the module reads and writes, including database tables, with each access routed through the interface or listed as an exception
- A runbook for the switch and for switching back
Included
- One module of up to 15 source files whose behaviour can be described as a small set of operations, in an application with a runnable test suite
- A written interface for the module: its operations, inputs, outputs and errors, agreed with you before any code moves
- Moving every caller, up to 40 call sites, onto that interface so that no code outside the module touches its internals
- A contract test suite of up to 25 cases, run against the module in the application
- A second implementation of the same interface running as a separate process that you can host, using the same database and the module's own tables (no data is moved or split), passing the same contract tests, with a configuration switch between the two
Not included
- Hosting, deploying or operating the separate module in production, which stay with your team
- Splitting the database into a separate one, or distributed transactions across the boundary
- Rewriting the module in another language, or adding features to it
- Extracting more than one module, which is a separate job for each
- Changing how the rest of the application is built or deployed
How we know it’s done
Agreed with you before work starts. Each check produces evidence you keep.
A search of the code outside the module finds no import or call of the module's internal functions and no query against its tables; every use goes through the interface
Evidence: The search output before and after, and the map of the module's data access with each access routed through the interface or listed as an accepted exception
The contract test suite of up to 25 cases passes against the module in the application, and passes unchanged against the separately running copy
Evidence: Two test run logs listing the same cases
With the switch set to each implementation in turn on staging, the application's existing tests and the agreed flows pass
Evidence: Test output and flow results for both settings
Switching from the separate copy back to the in-application module restores the same results for the agreed flows, rehearsed on staging
Evidence: The rehearsal log with before and after results
Sign-off. You review the interface, the contract tests and the data map, then merge and deploy under your own gates. Passing contract tests cover the behaviours agreed, not every possible use of the module.
If it fails. If the agreed acceptance checks do not pass, you do not pay and you keep the interface, the tests and the map of accesses.
When it fits, and when we stop
It fits when
- The module has up to 15 files, an owner who can describe what it does and a test suite that exercises it or a list of behaviours you can agree
- No more than 40 call sites outside the module use it, and they can be found by searching the code
- The module's own data is read and written only by the module, or the exceptions can be routed through the interface
- The application runs on a copy with test data and no live customers or payments
- Your team can host a separate process for the module on staging, and in production if you choose to switch, and operate it
We stop and tell you if
- The module shares in-memory state or database transactions with the rest of the application in a way that cannot be put behind an interface
- Other code reads or writes the module's tables in many places that cannot be listed and changed
- The module's behaviour cannot be exercised without production data or live external effects
- The call sites are generated dynamically and cannot be found by searching
- Nobody on your side can host and operate a separate process, even on staging: the seam alone is not covered by this fixed-price outcome, so ask for a quote
What could go wrong
Every change is a pull request your team merges, so it can be reverted. The configuration switch defaults to the module in its current place; switching back to it from the separate copy restores the earlier behaviour. No data is moved in this job: the separate process reads and writes the same database and the module's own tables, only through the interface, so there is nothing to reconcile when you switch back.
Scroll the table sideways to read it all.
| Risk | How we handle it |
|---|---|
| A caller or data access is missed and breaks when the module runs separately | Callers are found by search and then proved by moving them one at a time with the tests re-run, and the reviewer repeats the search independently. |
| The contract tests are weaker than the behaviour people rely on | The list of behaviours is agreed with a named person before tests are written, and each test is traced to an item on the list. |
| A network call adds failure modes the in-process call did not have | The interface states its errors explicitly, the contract tests include failure cases, and the switch lets you run the in-process version until you are satisfied. |
A second reviewer re-searches the code for any remaining access to the module's internals and its tables, checks that the contract tests are not weaker than the behaviour agreed, and re-runs both settings of the switch from the handover notes alone.
How we deliver
We arrange the work and independent review, then show you the result against the agreed checks. You keep authority over your systems.
- Agree the module, the list of its operations and the definition of done, then run the application's tests on a copy and record the baseline
- Find every caller and every data access of the module by searching the code, and write the map of what it reads and writes
- Write the interface and the contract tests against the module as it is, so the tests pass before anything moves
- Move each caller onto the interface one at a time, re-running the tests after each, until nothing outside the module touches its internals
- Build the separately running copy of the module against the same interface and run the same contract tests, then add the switch and test both settings
- Independent review of the interface, the caller changes and the data map, then hand over the pull requests, the evidence and the runbook for switching and switching back
This is a one-off job, not emergency cover or a subscription. We confirm eligibility, the total price, a start window and a delivery date before you accept. Work starts only after agreed inputs, secure access, any licences and necessary permissions are in place. Hosting, platform and supplier charges are excluded unless the written quote includes them. No charge or booking is created by an enquiry.
Need to keep it working?
Discuss a follow-on to extract the next module, or a monthly service that keeps the application's dependencies on supported versions.
Ongoing work is separately scoped and quoted: no monitoring, response-time guarantee or automatic subscription is included in this job.
Explore an ongoing engineering lane, or mention the responsibility you need in your enquiry.
What you can check
This is a new service. We have not delivered this job for a client yet.
Other ways to get this done
- Stopping after the seam, with the module still inside the application behind its interface, already removes most of the risk. That smaller scope is quoted separately from this job, which also builds the separately running copy; whether you switch to the copy is your decision after you see the tests.
- If the module is rarely changed and shares most of its data with the rest of the code, leaving it where it is and improving its tests may be the better investment.
Questions
Why not extract it straight into a new service?
Because most failures come from callers and data access that nobody listed. Making the boundary real first, with tests, finds them while everything is still in one place.
Do I have to run the module separately?
No. Whether you switch to the separate copy is your decision. The copy is part of this fixed job, so it needs somewhere to run, even if only on staging. The seam and contract tests alone are quoted separately.
Does the separate module get its own database?
Not in this job. The separate process uses the same database and the module's own tables, reached only through the interface. Splitting the database needs a data-ownership plan and is quoted separately.
Send an enquiry
Send us
- The language and framework, and the module you want separated and what it does
- The approximate number of files in it, and how many places call it
- Whether the module has its own database tables, and whether other code uses them
- Why you want it separate and how you would host it
Later, once you agree
- A controlled copy of the source with secrets removed, through the agreed company-controlled secure handoff
- How to run the application and its tests locally, with synthetic fixtures
- A named person who can confirm the module's intended behaviour
- A company-controlled secure handoff agreed before access: no live passwords, keys, private code or customer records by ordinary email.
You own the code, hosting and data. We work from an authorised copy with secrets removed and return pull requests that your team reviews, merges and deploys. We never ask for passwords or tokens in the first enquiry.
Email fallback: open your mail app
If website submission is unavailable, review and send the fallback email yourself. An email fallback is not a website receipt. Or write to hello@syntheticindustry.ai with “legacy-extract-one-module-behind-interface” as the subject.