Frankenstein sa programming ay code na binuo mula sa hindi tugmang mga bahagi ng iba't ibang teknolohiya, estilo, at arkitektura. Ayon sa pananaliksik ng ThoughtWorks Technology Radar (2024), 28% ng malalaking proyekto ay nagpapakita ng mga palatandaan ng Frankenstein syndrome — arkitektural na eklektisismo na lumilitaw kapag walang pinag-isang teknikal na pananaw. Sa pagkakatulad sa nobela ni Mary Shelley, gumagana ang naturang code, ngunit ang pagpapanatili nito ay nagiging bangungot.
Mga Pangunahing Punto
Frankenstein (Frankenstein code, Frankenstein pattern) ay isang antipattern kung saan ang isang software system ay binuo mula sa mga bahagi na hindi idinisenyo upang magtulungan. Tulad ng halimaw ni Frankenstein, ang naturang code ay maaaring gumana, ngunit ito ay pangit, hindi mahuhulaan, at mapanganib sa kaunting pagbabago.
Ang termino ay nagmula sa panitikan: sa nobela ni Mary Shelley na “Frankenstein, or the Modern Prometheus” (1818), isang siyentipiko ang lumikha ng isang buhay na nilalang mula sa mga pragmento ng katawan ng iba't ibang namatay na tao. Sa programming, ang pagkakatulad ay tumpak — ang mga developer ay kumukuha ng mga piraso ng iba't ibang framework, library, wika at pinagdikit-dikit ang mga ito, na nagreresulta sa isang gumagana ngunit nakakatakot na resulta.
Ang pagkakaiba ng Frankenstein sa spaghetti code ay nasa sukat at kalikasan ng problema. Ang spaghetti code ay isang magulong istraktura sa loob ng isang teknolohiyang stack. Ang Frankenstein ay eklektisismo sa antas ng arkitektura: iba't ibang teknolohiya, hindi tugmang paradigma, nagkakasalungatang mga diskarte sa loob ng isang sistema.
Ang arkitekturang microservices ay nagpapahintulot sa paggamit ng iba't ibang teknolohiya para sa iba't ibang serbisyo, ngunit sa kondisyon ng malinaw na mga hangganan at pamantayang protokol ng komunikasyon. Ang Frankenstein ay magulong paghahalo nang walang hangganan: REST at GraphQL sa isang controller, dalawang ORM sa isang module, SQL at NoSQL para sa iisang entity.
Ang kawalan ng teknikal na lider o arkitekto ang pangunahing sanhi. Kapag sa isang proyekto ay walang taong responsable para sa integridad ng arkitektura, bawat developer ay pumipili ng mga kasangkapan “para sa kanyang sarili”. Ang isa ay mahilig sa Spring, ang pangalawa sa Guice, ang pangatlo sa sariling DI. Ang resulta ay isang arkitektural na halo-halo.
Ang pagsasama ng mga proyekto ay ang pangalawang karaniwang sanhi. Dalawang koponan ang nag-develop ng kanilang mga module nang hiwalay gamit ang magkaibang stack. Kapag ang mga module ay kailangang pagsamahin sa isang aplikasyon, ang mga ito ay “dinidikit” lamang gamit ang mga adapter at intermediary layers. Ang resulta ay Frankenstein.
Ang mga pag-aari ng korporasyon ay ang ikatlong senaryo. Ang Kompanya A ay bumili ng Kompanya B at nais na isama ang produkto nito sa sarili nitong produkto. Sa halip na muling pagsusulat — pagdikit sa pamamagitan ng API, shared database, at mga workaround. Pagkalipas ng isang taon, ang sistema ay nagiging isang halimaw na walang nakakaintindi.
| Sanhi | Paglalarawan | Karaniwang resulta |
|---|---|---|
| Walang arkitekto | Bawat developer ay pumipili ng sariling stack | 3 magkaibang HTTP client sa isang module |
| Pagsasama ng proyekto | Dalawang produkto ay pinagsama sa isa | Dalawang ORM, dalawang paraan ng pag-log |
| M&A | Pag-aari ng kumpanya kasama ang produkto nito | Hibrida ng iba't ibang arkitektura at estilo |
| Mga eksperimento | Pagpapakilala ng bagong teknolohiya nang walang estratehiya | Java 8 + Java 21 feature sa isang file |
| Mga politikal na desisyon | Pagpapataw ng teknolohiya mula sa itaas nang walang konteksto | Enterprise framework para sa simpleng script |
Ang mga karanasang developer na gustong sumubok ng mga bagong teknolohiya sa produksyon ay kadalasang nagiging pinagmumulan ng Frankenstein. Sa halip na limitahan ang mga eksperimento sa isang nakahiwalay na module, ipinapasok nila ang eksperimental na code sa kritikal na bahagi ng sistema.
Isang klasikong halimbawa ay ang paggamit ng maraming ORM sa isang aplikasyon. Ang ilang module ay gumagamit ng Hibernate, ang iba ay MyBatis, at ang iba naman ay direktang JDBC query. Ang mga transaksyon ay nagiging hindi mapamahalaan, ang cache ay hindi pare-pareho, at ang bagong developer ay hindi alam kung aling diskarte ang pipiliin para sa bagong feature.
Ang pangalawang halimbawa ay ang paghahalo ng mga estilo ng arkitektura. Sa isang REST API controller ay may mga tawag sa SOAP service, direktang SQL query, access sa file system, at HTML generation. Ang ganitong aplikasyon ay imposibleng subukan, palawakin, o idokumento.
Ang pangatlong halimbawa ay isang teknolohiyang stack kung saan ang Python ay ginagamit para sa backend, Node.js para sa microservice, C# para sa desktop client, at Java para sa Android app, habang ang lahat ng business logic ay nakakalat sa pagitan ng mga ito nang walang malinaw na paghahati ng responsibilidad.
// frankenstein — pinaghalong estilo at teknolohiya
// callbacks, Promises, at async/await pinagsama
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// Promise sa loob ng callback
fetch("/api/data").then(function(data) {
// async/await sa loob ng then
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// malinis na code — pinag-isang async/await na estilo
async function getUserData(userId) {
const user = await db.query("SELECT * FROM users WHERE id = ?", [userId]);
const data = await fetch("/api/data/" + userId);
return await processData(user, data);
}
Isang database ay ginagamit nang sabay-sabay bilang SQL relational (may normalisasyon) at bilang NoSQL document-oriented (may JSON columns). Ang ilang query ay sa pamamagitan ng ORM, ang iba ay sa pamamagitan ng stored procedure, ang iba ay sa pamamagitan ng direktang SQL mula sa code. Ang schema ng database ay hindi dokumentado, ang mga migration ay nagkakasalungatan.
Ang komplikasyon ng onboarding ay ang unang kahihinatnan. Ang isang bagong developer ay dapat na marunong ng 5 wika, 3 framework, 2 estilo ng arkitektura upang maunawaan kung paano gumagana ang sistema. Ang onboarding ay tumatagal mula sa mga linggo hanggang mga buwan. Ayon sa LinkedIn (2023), ang mga proyektong may teknolohiyang eklektisismo ay nawawalan ng bagong empleyado nang 2 beses na mas madalas.
Ang hindi mahuhulaan ng pag-uugali ay ang pangalawang kahihinatnan. Ang pagbabago sa Python microservice ay maaaring biglang makasira ng Java module dahil gumagamit sila ng shared database nang walang malinaw na kontrata. Ang pag-debug ng mga ganitong problema ay nangangailangan ng sabay-sabay na kaalaman sa lahat ng teknolohiya sa stack.
Ang seguridad ay ang pangatlong kahihinatnan. Bawat teknolohiya sa stack ay nangangailangan ng sariling configuration ng seguridad, sariling patches, sariling monitoring. Ang pagpapanatili ng seguridad sa isang katanggap-tanggap na antas para sa 5–6 na magkakaibang teknolohiya ay halos imposible. Ang isa sa mga ito ay tiyak na magiging vulnerable.
Ang SonarQube ay maaaring sumukat ng teknikal na utang, ngunit hindi nito masusukat ang “arkitektural na utang” — ang hindi pagkakatugma ng mga bahagi. Ang utang na ito ay hindi lumilitaw sa mga babala ng linter, kundi sa kawalan ng kakayahang magdagdag ng bagong feature nang hindi binabago ang tatlong magkakaibang module na nakasulat sa iba't ibang teknolohiya.
Ang una at pinakamahalagang hakbang ay ang magtalaga ng arkitekto o tech lead na responsable para sa integridad ng teknolohiyang stack. Ang taong ito ay may veto sa pagpapakilala ng mga bagong teknolohiya nang walang arkitektural na pagsusuri. Hindi demokrasya, kundi responsableng nag-iisang desisyon sa mga pangunahing teknolohiya.
Ang pangalawa — ipatupad ang proseso ng Architecture Decision Record (ADR). Bawat makabuluhang desisyong arkitektural (pagpili ng database, framework, protocol) ay idodokumento bilang isang maikling teksto: konteksto, mga alternatibong isinaalang-alang, desisyong ginawa, mga kahihinatnan. Ang ADR ay iniimbak sa repository at available sa buong koponan.
Ang pangatlo — itakda ang prinsipyong “isang gawain — isang kasangkapan”. Para sa HTTP requests — isang client. Para sa ORM — isang library. Para sa logging — isang framework. Ang mga eksepsiyon ay pinapayagan lamang sa pamamagitan ng ADR na may katwiran. Kung may Axios na sa proyekto — huwag magdagdag ng fetch, kung may SLF4J na — huwag sumulat sa pamamagitan ng System.out.
Ang mga eksperimento ay pinapayagan, ngunit sa isang nakahiwalay na kapaligiran. Magtalaga ng module o serbisyo na maaaring muling isulat gamit ang bagong teknolohiya nang walang impluwensya sa iba pang sistema. Kung magtagumpay ang eksperimento — i-standardize ito sa pamamagitan ng ADR. Kung hindi — tanggalin nang walang kahihinatnan.
Ang inventarisasyon ay ang unang hakbang. Gumawa ng kumpletong mapa ng teknolohiyang stack: anong mga framework, library, wika, protokol ang ginagamit, sa anong mga module, at para sa anong mga gawain. Makikita mo ang laki ng problema: dobleng kasangkapan, nagkakasalungatang teknolohiya, hindi nagamit na dependencies.
Ang standardisasyon ay ang ikalawang hakbang. Pumili ng isang kasangkapan para sa bawat gawain. Halimbawa: tanging Hibernate para sa ORM, tanging SLF4J + Logback para sa logging, tanging REST para sa API. Idokumento ang pamantayan sa ADR. Simulan ang pagpapalit sa mga module kung saan ang eklektisismo ay nagdudulot ng pinakamaraming problema.
Ang estratehiyang Parallel Run ay ang ikatlong hakbang. Ang luma at bagong mga kasangkapan ay gumagana nang magkatulad hanggang sa mapatunayan ng bago ang pagiging maaasahan nito. Halimbawa, ang lumang HTTP client at ang bago ay gumagana nang sabay, ngunit ang bago ay para lamang sa bahagi ng mga request. Pagkatapos ng panahon ng pagpapatatag, ang luma ay tatanggalin.
// frankenstein — tatlong HTTP approach sa isang proyekto
// Module A: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// Module B: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// Module C: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// pinag-isang approach: RestTemplate para sa sync, WebClient para sa reactive
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
Ang teknikal na lider ay ang pangunahing kasangkapan sa paglaban sa Frankenstein. Hindi manager, hindi arkitekto sa ivory tower, kundi isang nagsasagawa ng developer na sumusulat ng code, nagre-review ng PR, at gumagawa ng mga desisyong arkitektural. Kung wala ang ganoong tao, ang proyekto ay tiyak na mahuhulog sa teknolohiyang eklektisismo.
Ang RFC (Request for Comments) ay isang proseso na hiram mula sa Open Source na komunidad. Bago ang pagpapakilala ng anumang makabuluhang teknolohiya, ang may-akda ay sumulat ng RFC: problema, iminungkahing solusyon, mga alternatibo, plano ng implementasyon. Ang koponan ay nagtatalakay, bumoboto, tumatanggap o tumatanggi. Ang RFC ay lumilikha ng transparency at pumipigil sa “tahimik” na mga desisyong arkitektural.
Ang radar ng teknolohiya (Technology Radar mula sa ThoughtWorks) ay isang kasangkapan para sa pagkakategorya ng mga teknolohiya: Adopt, Trial, Assess, Hold. Ang koponan ay regular na nagsusuri ng radar at nag-a-update ng mga status. Ito ay tumutulong na makilala ang “uso” mula sa “kapaki-pakinabang” at maiwasan ang pagpapakilala ng hindi pa napatunayang teknolohiya sa kritikal na code.
Ang pinakamahalagang kalidad ng arkitektura ay ang pagkakapare-pareho (consistency). Kahit ang hindi pinakamahusay na kasangkapan na ginagamit sa buong proyekto ay mas mahusay kaysa sa pinakamahusay na kasangkapan na ginagamit lamang sa isang module. Ang pagkakapare-pareho ay nagbabawas ng cognitive load, nagpapasimple ng onboarding, at ginagawang mahuhulaan ang code.
Mga Madalas Itanong
Ang polyglot persistence ay ang malay na paggamit ng iba't ibang database para sa iba't ibang gawain (PostgreSQL para sa transaksyon, Redis para sa cache, Elasticsearch para sa paghahanap). Ang Frankenstein ay magulong paghahalo nang walang estratehiya. Ang pagkakaiba ay sa pagkakaroon ng desisyong arkitektural: ang polyglot ay isang plano, ang Frankenstein ay ang kawalan nito.
Oo, at ito ay isang karaniwang problema. Kapag ang bawat microservice ay gumagamit ng sariling wika, database, protokol, at diskarte sa deployment nang walang sentralisadong pamantayan — lumilitaw ang isang distributed Frankenstein. Para sa microservices, mahalaga ang mga pangkalahatang pamantayan: pinag-isang protokol (REST/gRPC), pinag-isang format ng log, sentralisadong observability.
Huwag pagbawalan — gabayan. Hilingin sa may-akda ng RFC na: ilarawan kung bakit hindi angkop ang umiiral na solusyon, anong mga alternatibo ang isinaalang-alang, kung paano isasagawa ang migrasyon. Kadalasan sa proseso ng pagsulat ng RFC, ang developer mismo ay nauunawaan na ang bagong teknolohiya ay hindi kailangan. Kung ang RFC ay kapani-paniwala — ipatupad ito, ngunit may plano at limitasyon.
Una inventarisasyon, pagkatapos standardisasyon. Huwag subukang muling isulat ang lahat nang sabay-sabay. Pumili ng isang layer (halimbawa, HTTP clients o logging), pumili ng pinag-isang kasangkapan, sumulat ng ADR, at mag-migrate nang paunti-unti. Ang Strangler Fig method — palitan ang lumang mga bahagi nang isa-isa nang hindi hihinto ang aplikasyon.
Kung mas kaunti, mas mabuti. Perpekto — isang wika, isang framework, isang database, isang paraan ng pag-log. Makatotohanan — 2–3 wika (may malinaw na paghihiwalay), 1–2 database, 1–2 framework. Bawat karagdagang teknolohiya ay nagpapataas ng cognitive load ng koponan at gastos ng pagpapanatili.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din