Definition
- Default to reuse – Proven libraries and services are battle-tested and community-maintained.
- Build for differentiation – Build custom only when the capability is core intellectual property or a hard regulatory requirement.
- Five factors – Evaluate fit, time to value, total cost of ownership, control, and risk.
- Maintenance tail – Custom code is maintained by you forever; libraries are maintained by their community.
- Security rule – Never roll your own cryptography or security primitives.
- Partial reuse – Buy the commodity parts and build only the thin unique layer on top.
Imagine National Bank of India needs a new safe. Buying a certified, battle-tested safe from a vendor is almost always smarter than welding one in-house. But if the bank invents a genuinely new kind of vault that is its competitive edge, building it in-house makes sense.
Understanding the Concepts
What is this question really testing?
The interviewer wants to see a bias toward reuse for commodity problems and a clear, evidence-based justification when you do build. Knowing when to buy the safe versus when to build the vault is the test.
package com.bank.interview;
public class BuildVsBuy {
enum Decision { BUILD, BUY }
public static Decision decide(boolean isUnique, boolean isCoreToBusiness) {
return (isUnique && isCoreToBusiness) ? Decision.BUILD : Decision.BUY;
}
public static void main(String[] args) {
System.out.println("Retry logic: " + decide(false, false)); // BUY
System.out.println("Fraud model: " + decide(true, true)); // BUILD
}
}
What are the five evaluation factors?
Fit: does the existing solution meet the requirement? Time to value: library ships this week, custom takes months. Total cost: custom code is maintained forever. Control: core IP needs ownership. Risk: security functions must use vetted libraries.
package com.bank.interview;
import java.util.List;
public class FiveFactors {
record Factor(String name, String buyAdvantage, String buildAdvantage) {}
public static void main(String[] args) {
List<Factor> factors = List.of(
new Factor("Fit", "Meets 90%+ of need", "Meets 100% of unique need"),
new Factor("Time to value", "Ships this week", "Months of development"),
new Factor("Total cost", "Community-maintained", "You maintain forever"),
new Factor("Control", "Vendor controls roadmap", "You control everything"),
new Factor("Risk", "Vetted security", "Subtle bugs possible")
);
factors.forEach(f -> System.out.println(f.name() + ": BUY=" + f.buyAdvantage() + " BUILD=" + f.buildAdvantage()));
}
}
When did you choose to reuse at National Bank of India?
Retry logic for flaky downstream payment calls. Battle-tested libraries handle backoff, jitter, and limits correctly. Custom retry code is easy to write badly.
package com.bank.service;
public class ReuseExample {
public static void main(String[] args) {
// Reuse: one dependency, proven, community-maintained
System.out.println("Retry logic: used Spring Retry library");
System.out.println("Why: commodity problem, battle-tested, zero maintenance");
System.out.println("Proud of the code I did NOT have to write.");
}
}
When did you choose to build?
The fraud-scoring rules encode the bank's proprietary risk model. No off-the-shelf product fit more than twenty percent. This is core IP.
package com.bank.service;
public class BuildExample {
public static void main(String[] args) {
System.out.println("Fraud model: built from scratch");
System.out.println("Why: proprietary risk logic, core IP, no product fits > 20%");
System.out.println("Control: we own the model, can evolve it with our data");
}
}
Why is the maintenance tail the hidden cost?
Code you write is maintained by you for years: bug fixes, upgrades, on-call burden. Libraries are maintained by their community.
package com.bank.interview;
public class MaintenanceTail {
public static void main(String[] args) {
System.out.println("Year 0: Build cost = 2 weeks");
System.out.println("Year 1-5: Maintenance cost = 1 week/year x 5 = 5 weeks");
System.out.println("Total custom cost: 7 weeks over 5 years");
System.out.println("Library cost: 1 day setup + zero maintenance");
}
}
Why should you never roll your own crypto?
For security-critical functions, reusing a vetted library is almost always safer than custom code. Subtle mistakes in crypto are catastrophic.
package com.bank.service;
import java.security.MessageDigest;
public class NeverRollYourOwn {
public static void main(String[] args) throws Exception {
// Always use the standard library
MessageDigest md = MessageDigest.getInstance("SHA-256");
System.out.println("Use: MessageDigest.getInstance('SHA-256')");
System.out.println("Never: write your own hash function");
}
}
What is the best-of-both approach?
Buy the commodity parts and build only the thin unique layer on top. This gives the best time-to-value with the right control.
package com.bank.interview;
public class PartialReuse {
public static void main(String[] args) {
System.out.println("Commodity (buy): retry, circuit breaker, serialization");
System.out.println("Unique (build): fraud scoring model, proprietary rules");
System.out.println("Result: fast delivery + full control where it matters");
}
}
What are common interview follow-up questions?
Expect: "What if the library had a vulnerability?" (we track CVEs and update), "Did you ever regret building?" (only when the maintenance became a burden), "How do you evaluate a library?" (community, security, license, fit).
package com.bank.interview;
public class BuildBuyFollowUps {
public static void main(String[] args) {
System.out.println("Library vulnerability? -> Track CVEs, update promptly");
System.out.println("Regret building? -> Only when maintenance exceeded expectations");
System.out.println("Evaluate library? -> Community, security history, license, fit");
}
}
Visual Overview
┌────────────────────────────────────────────────────────┐ │ Build vs Buy Decision Framework │ ├────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────────────────────────────┐ │ │ │ Is the need unique AND core to biz? │ │ │ └──────────┬─────────────┬─────────────┘ │ │ │ │ │ │ YES ▼ NO ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ BUILD │ │ BUY/REUSE │ │ │ │ (own the │ │ (proven, │ │ │ │ IP and │ │ community │ │ │ │ control) │ │ maintained)│ │ │ └──────────────┘ └──────────────┘ │ │ │ │ Examples at National Bank of India: │ │ ┌─────────────────┬────────────────────┐ │ │ │ BUY │ BUILD │ │ │ │ Retry logic │ Fraud scoring model│ │ │ │ Circuit breaker │ Proprietary rules │ │ │ │ Crypto (SHA-256)│ Core risk engine │ │ │ └─────────────────┴────────────────────┘ │ │ │ │ Best: buy commodity + build unique thin layer │ └────────────────────────────────────────────────────────┘
Key Takeaway
I have made the build-versus-buy call in both directions on the same project at National Bank of India, and that contrast shows how I decide. For retry logic on flaky downstream payment calls, I reused a battle-tested library because it is a completely solved commodity problem and the maintenance tail of custom retry code would have been mine forever.
For our fraud-scoring rules, I built from scratch because the rules encode the bank's proprietary risk model : no off-the-shelf product fit more than twenty percent, and this capability is core intellectual property. Building gave us the control and differentiation we needed.
The result was the best of both: we shipped quickly by reusing the proven library, and we invested custom effort only where it created real, unique value. We did not waste months rebuilding a commodity and we did not compromise our differentiating capability.
My default is to reuse for commodity and security-sensitive problems, and build only when the need is genuinely unique or core. I also weigh the long maintenance cost heavily, because that is the hidden price juniors underestimate.
Remember one sentence: Default to reusing proven solutions for commodity problems, and build custom only when the need is genuinely unique or core to the business.
---