Appearance
Single‑Function Philosophy for MARS Engine
TL;DR - In MARS Engine every API or library file should answer one question or perform one atomic action. Keep it stateless, explicit, and easy to include elsewhere.
Why keep functions atomic in MARS Engine?
| Benefit | What it looks like in MARS |
|---|---|
| Clarity | You can open a file and know its only job-for example lib/math/roundPrice always rounds, it never writes JSON. |
| Composability | Single‑purpose files can be chained with include() or called from other APIs without refactor. |
| Testability | Pure logic files can be executed from a simple test API. |
| Scalability | Small APIs start instantly and consume less server time-perfect for MARS’s pay‑per‑request model. |
| Reusability | The same helper can be added to any project by copying one file or publishing a snippet to your team. |
Core Guidelines
- One Responsibility – a file either calculates tax or writes a PDF, never both.
- Explicit I/O Contracts – read using
param()/request.header(); write usingwrite(). Return a value if it’s a library file, never rely on globals. - Stateless by Default – fetch or persist data with
db.query(); don’t cache inside the module. - Pure When Possible – library files should be deterministic and side‑effect free. If you must call the network, wrap that in its own file.
- Precise Naming –
validateCouponis better thanutils2. - ≤ 40 LOC Rule – when a file creeps past ~40 logical lines of JavaScript split it up.
Recommended Structure
text
api/
└─ orders/
├─ calculateTotal # library include only
├─ applyDiscount
├─ validateCoupon
└─ checkout # orchestrator API (POST)
lib/
└─ orders/
├─ calculateTotal
├─ applyDiscount
└─ validateCouponLibrary file: lib/orders/calculateTotal
js
// Exports exactly one thing – a pure function
exports.calculateTotal = function(items) {
let sum = 0;
for (let i = 0; i < items.length; i++)
sum += +items[i].price || 0;
return sum;
};Orchestrator API: api/orders/checkout
js
const { calculateTotal } = include('lib/orders/calculateTotal');
const { applyDiscount } = include('lib/orders/applyDiscount');
const { validateCoupon } = include('lib/orders/validateCoupon');
const items = param('items', []);
const couponCode = param('coupon', null);
// fail fast if coupon invalid
if (!validateCoupon(couponCode)) {
write('status', 'ERR');
write('message', 'Invalid coupon');
exit();
}
const subtotal = calculateTotal(items);
const total = applyDiscount(subtotal, couponCode);
write('total', total); // single responsibility: pricingAnti‑Patterns
| Smell | Why it’s toxic in MARS | Cure |
|---|---|---|
| Kitchen‑Sink API | Long files mix DB, auth, email, and HTML-slow cold‑starts, hard rollbacks | Break into libraries + orchestrator |
| Hidden Side Effects | Updating DB inside calculateTotal surprises callers | Move side effect to its own API (storeOrder) |
| Generic Names | helper.js gives no clue in file tree | Rename to string/slugify |
| Global State | Storing mutable data on shared between requests breaks concurrency | Pass arguments or use DB |
When One File Isn't Enough
- Validation + Persistence – keep
validateCouponpure, then havesaveCouponUsagein a second file. - External Calls – wrap net requests in their own
net‑focused library so the rest of your codebase stays testable. - Complex Workflows – use an orchestrator API that only composes pure helpers and side‑effect files.
Key Takeaways
- Think file‑level single responsibility: each LIB or API does one thing.
- Pure helpers make MARS Engine faster (cold‑start) and cheaper (less CPU per call).
- Clear boundaries simplify rollbacks-if
sendEmailfails the DB transaction incheckoutcan still commit safely.
Commit to single‑function files and your MARS Engine projects stay lean, predictable, and fun to maintain.