Frankenşteyn proqramlaşdırmada — müxtəlif texnologiyaların, üslubların və arxitekturaların uyğum olmayan hissələrindən yığılmış koddur. ThoughtWorks Technology Radar (2024) tədqiqatına görə, böyük layihələrin 28%-i Frankenşteyn sindromunun əlamətlərini daşıyır — vahid texniki baxış olmadıqda yaranan arxitektura eklektikası. Meri Şelli romanına bənzətmələ, belə bir kod işləyir, lakin onun dəstəklənməsi kabusa çevrilir.
Başlıca
Frankenşteyn (Frankenstein code, Frankenstein pattern) — bu anti-nümunədir, burada proqram sistemi birgə iş üçən nəzərdə tutulmayan hissələrdən yığılır. Frankenşteynin canavari kimi, belə bir kod işləyə bilər, lakin o çirkin, gözlɘnilməz və ən kiçik dəyişikliklərdə təhlükəlidir.
Termin ədəbiyyatdan gəlir: Meri Şellinin «Frankenşteyn, yaxud Müasir Prometey» (1818) romanında alim müxtəlif ölü insanların bədən parçalarından canlı varlıq yaratdı. Proqramlaşdırmada bənzətmə dəqiqdir — tərtibatçılar müxtəlif freymvorklərin, kitabxanaların, dillərin parçalarını götürür və onları «candarma» yapışdırır, işləyən, lakin dəhşətli nəticə əldə edirlər.
Frankenşteynin spagetti koddan fərqi problem miqyası və təbiətindədir. Spagetti-kod — bir texnoloji yığın daxilində qarışıq quruluşdur. Frankenşteyn — arxitektura səviyyəsində eklektikadır: müxtəlif texnologiyalar, uyğum olmayan paradiqmalar, bir sistem daxilində ziddiyyətli yanaşmalar.
Mikroxidmət arxitekturası müxtəlif xidmətlər üçün müxtəlif texnologiyaların istifadəsinə icazə verir, lakin dəqiq sərhədlər və standartlaşdırılmış ünsiyyət protokolları şərti ilə. Frankenşteyn — sərhədsiz xaotik qarışdırmadır: bir kontrollerdə REST və GraphQL, bir moduldə iki ORM, bir varlıq üçün SQL və NoSQL.
Texniki liderin və ya memarın olmaması — əsas səbəb. Layihədə arxitektura bütövlüyünə cavabdeh şəxs olmadıqda, hər tərtibatçı alətləri özünə uyğun seçir. Biri Spring-i sevir, digəri — Guice, üçüncü — öz DI-ni yazır. Nəticə — arxitektura vinaqreti.
Layihələrin birləşməsi — ikinci geniş yayılmış səbəb. İki komanda modullarını müstəqil, fərqli texnoloji yığınlardan istifadə edərək inkişaf etdirdi. Modulları bir tətbiqdə birləşdirmək lazım olduqda, onlar sadəcə adapterlərlə «byapışdırılır». Nəticə Frankenşteyndir.
Korporativ satınalmalar — üçüncü ssenari. Şirkət A şirkət B-ni aldı və onun məhsulunu öz məhsuluna inteqrasiya etmək istəyir. Yenidən yazmaq əvəzinə — API vasitəsilə yapışdırma, ümumi verilənlər bazaları və ələştirmələr. Bir ildən sonra sistem heç kimin anlamadığı canavarı çevrilir.
| Səbəb | Təsvir | Nəticə |
|---|---|---|
| Memar yoxdur | Hər tərtibatçı öz yığınını seçir | Bir moduldə 3 fərqli HTTP klienti |
| Layihə birləşməsi | İki məhsul birinə yapışdırılır | İki ORM, iki loglama üsulu |
| M&A | Şirkətin məhsulu ilə satın alınması | Müxtəlif arxitektura və üslubların hibridi |
| Təcrübələr | Yeni texnologiyaların strategiyasız tətbiqi | Bir faylda Java 8 + Java 21 xüsusiyyətləri |
| Siyasi qərarlar | Texnologiyanın kontekst nəzərə alınmadan yuxarıdan tətbiqi | Sadə skript üçün Enterprise-freymvork |
Təcrübəli tərtibatçılar yeni texnologiyaları istehsalatda sınamaq istəyən, tez-tez Frankenşteynin mənbəyinə çevrilirlər. Təcrübələri təcrid olunmuş modulla məhdudlaşdırmaq əvəzinə, eksperimental kodu sistemin kritik hissəsinə daxil edirlər.
Klassik nümunə — bir tətbiqdə bir neçə ORM-in istifadəsi. Modulların bir hissəsi Hibernate, bir hissəsi — MyBatis, bir hissəsi isə birbaşa JDBC sorğuları istifadə edir. Tranzaksiyalar idarəolunmaz olur, keş — uyğunsuz, yeni tərtibatçı isə yeni funksiya üçün hansı yanaşmanı seçəcəyini bilmir.
İkinci nümunə — arxitektura üslublarının qarışdırılması. REST API kontrollerində SOAP xidmətlərinə çağırışlar, birbaşa SQL sorğuları, fayl sisteminə müraciət və HTML generasiyası var. Belə bir tətbiqi test etmək, genişləndirmək və ya sənədləşdirmək mümkün deyil.
Üçüncü nümunə — texnoloji yığın: Python backend üçün, Node.js — mikroxidmət üçün, C# — desktop klienti üçün, Java isə Android tətbiqi üçün istifadə olunur, lakin bütün biznes məntiqi onların arasında aydın məsuliyyət bölgüsü olmadan yayılıb.
// frankenstein — qarışıq üslublar və texnologiyalar
// callbacks, Promises və async/await birləşdirilmiş
// callbacks
db.query("SELECT * FROM users", function(err, rows) {
if (err) handleError(err);
// callback daxilində Promise
fetch("/api/data").then(function(data) {
// then daxilində async/await
(async () => {
const result = await processData(data);
sendResponse(result);
})();
});
});
// təmiz kod — vahid async/await üslubu
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);
}
Bir verilənlər bazası eyni anda həm SQL relasiyalı (normalizasiya ilə) həm də NoSQL sənəd-yönümlü (JSON sütunları ilə) istifadə olunur. Sorğuların bir hissəsi ORM vasitəsilə, bir hissəsi — saxlanılan prosedurlarla, bir hissəsi — koddan birbaşa SQL ilə yerinə yetirilir. Verilənlər bazası sxemi sənədləşdirilməyib, miqrasiyalar ziddiyyətlidir.
Onboardinqin çətinliyi — ilk nəticə. Yeni tərtibatçı sistemin necə işlədiyini anlamaq üçün 5 dil, 3 freymvork, 2 arxitektura üslubu bilməlidir. Onboardinq həftələrdən aylara uzanır. LinkedIn (2023) məlumatlarına görə, texnoloji eklektikası olan layihələr yeni işçiləri 2 dəfə daha tez-tez itirir.
Davranışın gözlɘnilməzliyi — ikinci nəticə. Python mikroxidmətindəki dəyişiklik gözlɘnilmədən Java modulunu poza bilər, çünki onlar aydın müqavilələr olmadan ümumi verilənlər bazasından istifadə edirlər. Belə problemlərin aradan qaldırılması yığındakı bütün texnologiyaların eyni anda bilinməsini tələb edir.
Təhlükəsizlik — üçüncü nəticə. Yığındakı hər bir texnologiya öz təhlükəsizlik konfiqurasiyasını, öz yamalarını, öz monitorinqini tələb edir. 5–6 müxtəlif texnologiya üçün məqbul səviyyədə təhlükəsizliyi qorumaq praktiki olaraq qeyri-mümkündür. Onlardan biri qaçınılmaz olaraq zəif olacaq.
SonarQube texniki borcu ölçə bilər, lakin «memarlıq borcunu» ölçə bilməz — komponentlərin uyğunsuzluğunu. Bu borc linterin xəbərdarlıqlarında deyil, müxtəlif texnologiyalarda yazılmış üç fərqli modulu dəyişdirmədən yeni funksiya əlavə etməyin mümkünsüzlüyündə özünü göstərir.
Əsas və ən vacib addım — texnoloji yığının bütövlüyünə cavabdeh olan memar və ya tech lead təyin etmək. Bu şəxs memarlıq rəyi olmadan yeni texnologiyaların tətbiqinə veto hüququna malikdir. Demokratiya deyil, əsas texnologiyalar üzrə məsuliyyətli tək şəxs qərarı.
İkinci — Architecture Decision Record (ADR) prosesini tətbiq etmək. Hər bir əhəmiyyətli memarlıq qərarı (verilənlər bazası, freymvork, protokol seçimi) qısa mətn şəklində sənədləşdirilir: kontekst, nəzərdən keçirilmiş alternativlər, qəbul edilmiş qərar, nəticələr. ADR-lər depoda saxlanılır və bütün komanda üçün əlçatandır.
Üçüncü — «bir tapşırıq — bir alət» prinsipini müəyyən etmək. HTTP sorğuları üçün — bir klient. ORM üçün — bir kitabxana. Loglama üçün — bir freymvork. İstisnalar yalnız ADR vasitəsilə əsaslandırma ilə icazəlidir. Layihədə artıq Axios varsa — fetch əlavə etməyin, SLF4J varsa — System.out vasitəsilə yazmayın.
Eksperimentlər icazəlidir, lakin təcrid olunmuş mühitdə. Sistemin qalan hissəsinə təsir etmədən yeni texnologiyada yenidən yazıla biləcək bir modul və ya xidmət ayırın. Eksperiment uğurlu olarsa — ADR vasitəsilə standartlaşdırın. Yoxsa — nəticəsiz silin.
Inventarizasiya — ilk addım. Texnoloji yığının tam xəritəsini tərtib edin: hansı freymvorklar, kitabxanalar, dillər, protokollar istifadə olunur, hansı modullarda və hansı tapşırıqlar üçün. Problemin miqyasını görəcəksiniz: alətlərin təkrarlanması, ziddiyyətli texnologiyalar, istifadə olunmayan asılılıqlar.
Standartlaşdırma — ikinci addım. Hər tapşırıq üçün bir alət seçin. Məsələn: ORM üçün yalnız Hibernate, loglama üçün yalnız SLF4J + Logback, API üçün yalnız REST. Standartı ADR-də sənədləşdirin. Eklektikanın ən çox problem yaratdığı modullardan dəyişdirməyə başlayın.
Parallel Run strategiyası — üçüncü addım. Köhnə və yeni alətlər paralel işləyir, yeni öz etibarlılığını sübut edənə qədər. Məsələn, köhnə və yeni HTTP klienti eyni anda işləyir, lakin yeni — yalnız sorğuların bir hissəsi üçün. Sabitləşmə dövründən sonra köhnəsi silinir.
// frankenstein — bir layihədə üç HTTP yanaşması
// Modul A: OkHttp
OkHttpClient client = new OkHttpClient().newCall(request);
// Modul B: RestTemplate (Spring)
restTemplate.getForObject(url, String.class);
// Modul C: java.net.HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
// vahid yanaşma: sinxron üçün RestTemplate, reaktiv üçün WebClient
@Autowired
private RestTemplate restTemplate;
public String callApi(String url) {
return restTemplate.getForObject(url, String.class);
}
Texniki lider — Frankenşteynlə mübarizənin əsas vasitəsidir. Menecer deyil, fil sümüyü qüləsindəki memar deyil, kod yazan, PR-ları nəzərdən keçirən və memarlıq qərarları qəbul edən praktikant tərtibatçı. Belə bir şəxs olmadan layihə qaçınılmaz olaraq texnoloji eklektikaya sürüklənir.
RFC (Request for Comments) — Open Source icmalarından götürülmüş proses. Hər bir əhəmiyyətli texnologiyanın tətbiqindən əvvəl müəllif RFC yazır: problem, təklif olunan həll, alternativlər, tətbiq planı. Komanda müzakirə edir, səs verir, qəbul edir və ya rədd edir. RFC şəffaflıq yaradır və «“səssiz”» memarlıq qərarlarının qarşısını alır.
Texnoloji radar (ThoughtWorks-dan Technology Radar) — texnologiyaların kateqoriyalaşdırılması aləti: Adopt, Trial, Assess, Hold. Komanda radarı mütəmadi olaraq nəzərdən keçirir və statusları yeniləyir. Bu, «dəbçü» ilə «faydalı»nı ayırmağa və yoxlanılmamış texnologiyaların kritik koda daxil edilməsinin qarşısını almağa kömək edir.
Əhəmiyyətli arxitektura keyfiyyəti — ardıcıllıqdır (consistency). Bütün layihədə istifadə olunan ən yaxşı olmayan alət belə, yalnız bir moduldə istifadə olunan ən yaxşı alətdən yaxşıdır. Ardıcıllıq koqnitiv yükü azaldır, onboardinqi sadələşdirir və kodu proqnozlaşdırıla bilən edir.
Tez-tez verilən suallar
Polyglot persistence — müxtəlif tapşırıqlar üçün müxtəlif verilənlər bazalarının şürlu istifadəsidir (PostgreSQL tranzaksiyalar üçün, Redis keş üçün, Elasticsearch axtarış üçün). Frankenşteyn — strategiyasız xaotik qarışdırma. Fərq memarlıq qərarının mövcudluğundadır: polyglot — bu plandır, Frankenşteyn — onun olmaması.
Bəli, və bu tez-tez rast gəlinən problemdir. Hər bir mikroxidmət mərkəzləşdirilmiş standartlar olmadan öz dilini, öz verilənlər bazasını, öz protokolunu və öz yerləşdirmə yanaşmasını istifadə etdikdə — paylanmış Frankenşteyn yaranır. Mikroxidmətlər üçün ümumi standartlar vacibdir: vahid protokol (REST/gRPC), ümumi log formatı, mərkəzləşdirilmiş observability.
Qadağan etməyin — istiqamətləndirin. RFC müəllifinə təklif edin: mövcud həllin niyə uyğun olmadığını, hansı alternativlərin nəzərdən keçirildiyini, necə miqrasiya edəcəyini təsvir etsin. Tez-tez RFC yazma prosesində tərtibatçı özü başa düşür ki, yeni texnologiya lazım deyil. RFC inandırıcıdırsa — tətbiq edin, lakin plan və məhdudiyyətlərlə.
Əvvəlcə inventarizasiya, sonra standartlaşdırma. Hər şeyi bir anda yenidən yazmağa çalışmayın. Bir təbəqə ayırın (məsələn, HTTP-klientlər və ya loglama), vahid alət seçin, ADR yazın və tədricən miqrasiya edin. Strangler Fig metodu — köhnə komponentləri bir-bir yeniləri ilə əvəz edin, tətbiqin işini dayandırmadan.
Nə qədər az, o qədər yaxşı. Ideal — bir dil, bir freymvork, bir verilənlər bazası, bir loglama üsulu. Realist — 2–3 dil (aydın bölgü ilə), 1–2 verilənlər bazası, 1–2 freymvork. Hər əlavə texnologiya komandanın koqnitiv yükünü və dəstək dəyərini artırır.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun