„Məndə lokal işləyir” (ing. „Works on my machine”) — tərtibatçının öz lokal mühitində səhvi təkrarlaya bilmədiyi halda işlətdiyi klassik ifadədir, baxmayaraq ki, səhv komandanın digər üzvlərində və ya istehsal mühitində sabit şəkildə özünü göstərir. Vəziyyət konfiqurasiya, asılılıqların versiyaları, əməliyyat sistemi və ya məlumatlardakı fərqlər səbəbindən yaranır. Stack Overflow Survey 2023-ə görə, tərtibatçıların 58%-i ayda ən azı bir dəfə bu ifadəni işlədir, 31%-i isə həftəlik. Kodun niyə hər yerdə eyni işləmədiyini və mühiti necə standartlaşdıracağımızı öyrənirik.
Əsas məqamlar
„Məndə lokal işləyir” — tərtibatçının həmkarı və ya testçi səhv barədə xəbər verdikdə işlətdiyi ifadədir, ancaq tərtibatçının maşınında bu səhv təkrarlanmır. Zahirən bu problemin inkarı kimi görünür, lakin texniki cəhətdən vəziyyət realdır: kod həqiqətən bir mühitdə işləyib digərində çökə bilər. Konfiqurasiyanın bir bitindəki fərq — və tətbiqin davranışı kökündən dəyişir.
Bu ifadə IT icmasında mem halına gəldi, çünki o həm doğru, həm də faydasızdır. Tərtibatçı nöqteyi-nəzərindən — kod həqiqətən onun maşınında işləyir. Komanda nöqteyi-nəzərindən — problem mövcuddur və onu həll etmək lazımdır, bəhanə axtarmaq yox. Vəziyyətin yumoru ondadır ki, tərtibatçı doğru deyir, amma bu həqiqət səhvi düzəltməyə kömək etmir. Mem o qədər populyardır ki, ona Reddit, XKCD və DevOps konfranslarında minlərlə post həsr olunub.
Proseslər nöqteyi-nəzərindən „məndə lokal işləyir” ifadəsi mühitin təkrarlanma qabiliyyəti ilə bağlı problemlərin göstəricisidir. Əgər iki tərtibatçı eyni kodda eyni nəticəni əldə edə bilmirsə — demək mühitin qurulması prosesi standartlaşdırılmayıb. DevOps təcrübəsi deyir: mühit əl hərəkətləri olmadan repozitoriyadan bir əmrlə təkrarlana bilməlidir.
Lokal mühit tərtibatçınınki demək olar ki, həmişə istehsal mühitindən fərqlənir. Tərtibatçı macOS və ya Windows istifadə edir, server isə Linux-da işləyir. Müxtəlif əməliyyat sistemləri müxtəlif fayl sistemlərinə, kodlaşdırmalara, axın vaxtlarına və sistem çağırışlarına malikdir. Hər iki mühit Linux olsa belə — nüvə versiyası, glibc, OpenSSL fərqlənə bilər.
İkinci səbəb — quraşdırılmış proqram təminatı dəsti. Tərtibatçının maşınında Node.js 20 qlobal versiyası quraşdırılmış ola bilər, CI/CD konfiqurasiyasında isə versiya 18 göstərilib. Yaxud tərtibatçı lokal olaraq PostgreSQL 16, istehsalda isə PostgreSQL 14 istifadə edir. Kiçik versiya fərqləri çox vaxt nəzərə çarpmır, lakin əsas yeniləmələr SQL sorğularının davranışını dəyişə bilər. npm Inc.-ə görə, asılılıqlarla bağlı səhvlərin 67%-i patch-versiyalardakı fərqdən qaynaqlanır.
Üçüncü səbəb — şəbəkə şəraiti. Lokal maşında gecikmələr, ötürmə qabiliyyəti məhdudiyyətləri və DNS problemləri yoxdur. İstehsalda xarici API-ə hər sorğu 5 ms əvəzinə 500 ms çəkə bilər. Taymautlar, təkrar cəhd məntiqi, race conditions — bütün bu problemlər yalnız real yük və real şəbəkə şəraitində özünü göstərir. Toxiproxy kimi alətlər vasitəsilə şəbəkə emulyasiyası bu problemləri yerləşdirmədən əvvəl aşkarlamağa kömək edir.
Birinci səbəb — məlumatların olmaması. Tərtibatçı test fixturları ilə işləyir, istehsalda isə gözlənilməz dəyərlərlə milyonlarla yazı var. Tərtibatçının məcburi hesab etdiyi sahədə NULL, adda Unicode simvolu, çox uzun sətir — bütün bunlar sintetik məlumatları olan lokal bazada təkrarlanmayan səhvlərə səbəb ola bilər.
İkinci səbəb — müxtəlif kompilasiya və qurma bayraqları Buraxılış yığımı (Release/Distribution) debug yığımından (Debug) fərqlənə bilər. Kompilator optimizasiyaları, debug jurnallarının silinməsi, funksiyaların inline edilməsi — bütün bunlar səhvləri gizlədə və ya əksinə, üzə çıxara bilər. Tipik nümunə: debug yığımında dəyişənlərin fərqli inisiallaşdırma sırası səbəbindən release yığımında çökən assert işləyir.
Üçüncü səbəb — lokal keş və müvəqqəti fayllar. Tərtibatçı səhvi görməyə bilər, çünki brauzerdə köhnə skriptlər keşlənib, Redis-də köhnəlmiş məlumatlar saxlanılır, fayl sistemində isə əvvəlki işə salmalardan müvəqqəti fayllar qalıb. Təmiz işə salma (inkognito rejimi, keşin təmizlənməsi, fresh install) çox vaxt „öz-özünə” görünməyən səhvi təkrarlayır.
Dördüncü səbəb — qlobal və lokal asılılıqların münaqişəsi. Ruby gems, Python pip, Node.js npm kimi alətlər kodun lokal işləməsinə „kömək edən”, lakin istehsalda olmayan qlobal quraşdırılmış paketlərə malik ola bilər. Virtual mühitlərdən (virtualenv, venv, nvm) istifadə layihəni qlobal quraşdırmalardan təcrid edir və mühiti təkrarlana bilən edir.
„Məndə lokal işləyir” ifadəsi komandada inamı məhv edir. Tərtibatçı müntəzəm olaraq səhvləri təkrarlaya bilmirsə, həmkarları onun səriştəsinə və ya test etmənin hərtərəfliliyinə şübhə etməyə başlayır. Zamanla bu mikromenecmentə gətirib çıxarır: hər dəyişiklik ikinci tərtibatçı tərəfindən yoxlanılmalı olur və bu da inkişafı ləngidir. Google Project Aristotle-a görə, komandada psixoloji təhlükəsizlik birbaşa məhsuldarlığa təsir edir, mühit haqqında daimi mübahisələr isə onun azalmasının amillərindən biridir.
İkinci problem — kod icmalının ləngiməsi. Tərtibatçı səhvi lokal olaraq təkrarlaya bilmirsə, o, həmkarının pull request-ini „məndə işləyir — demək problem səndədir” sözləri ilə rədd edə bilər. Bu, münaqişələrə səbəb olur və funksiyaların çatdırılmasını gecikdirir. Mühitin standartlaşdırılması bu münaqişəni aradan qaldırır: əgər hər iki tərtibatçı eyni Docker konteynerində işləyirsə, „kimdə işləyir” sualı mənasını itirir.
Üçüncü problem — trekerdə səhvlərin itirilməsi. Tərtibatçıda „təkrarlanmayan” səhvlər çox vaxt „Təkrarlana bilmir” qeydi ilə bağlanır. Bir aydan sonra səhv istehsalda üzə çıxır və onun düzəldilməsi 10 dəfə baha başa gəlir. Qayda: əgər səhv ən azı bir nəfərdə təkrarlanırsa — o, tərtibatçıda işləsə də işləməsə də mövcuddur.
Birinci və ən təsirli üsul — Docker. Bütün layihə əlavə hərəkətlər olmadan docker-compose up vasitəsilə işə düşməlidir. Məlumat bazası, keş, mesaj növbəsi, veb-server — hər şey konteynerlərdə qaldırılır. Tərtibatçı yalnız Docker və Git quraşdırır. Qalanı — konteynerlərin içərisindədir. Bu, ƏS-dən asılı olmayaraq komandanın bütün üzvlərinin eyni mühitə malik olmasını təmin edir.
İkinci üsul — versiya menecerləri. Docker mümkün deyilsə (lisenziya məhdudiyyətləri, köhnə infrastruktur), nvm (Node.js), rbenv (Ruby), pyenv (Python), sdkman (Java) istifadə edin. Versiya menecerləri layihə çərçivəsində dillərin və alətlərin versiyalarını dəyişməyə imkan verir. .nvmrc, .ruby-version, .python-version faylları repozitoriyada olmalı və CI/CD tərəfindən yoxlanmalıdır.
Üçüncü üsul — Vagrant virtual maşınlar üçün. Vagrant VirtualBox və ya VMware üzərində müəyyən ƏS və konfiqurasiya ilə virtual maşın qaldırır. VM daxilində bütün asılılıqlar provisioning-skriptlər (shell, Ansible, Puppet) vasitəsilə quraşdırılır. Vagrant Docker-dən ağırdır, lakin ƏS səviyyəsində tam izolyasiya verir — Linux nüvəsinin konkret versiyasından asılı olan layihələr üçün faydalıdır.
Dördüncü — makefile və bootstrap-skriptlər. Hətta sadə Makefile install, test, build, clean məqsədləri ilə rutin hərəkətləri standartlaşdıra bilər. make install əmri bütün asılılıqları quraşdırmalı, verilənlər bazasını qurmalı və test məlumatlarını yaratmalıdır. Bütün tərtibatçılar üçün vahid giriş nöqtəsi mühitin qurulmasında əl səhvlərini aradan qaldırır.
Əsas alət — asılılıqların lock-faylları. package-lock.json (npm), yarn.lock (Yarn), Podfile.lock (CocoaPods), pubspec.lock (Flutter) hər paketin dəqiq versiyasını təsbit edir. Lock-fayl olmadan, asılılıqları müxtəlif vaxtlarda quraşdıran iki tərtibatçı fərqli kiçik versiyalar əldə edə bilər. Lock-fayl repozitoriyada olmalı və əl ilə redaktə edilməməlidir.
İkinci alət — repozitoriyada .env.example faylı. Şərhlərlə mühit dəyişənlərinin şablon faylı. Tərtibatçı onu .env faylına kopyalayır və öz dəyərlərini doldurur. CI/CD boru xətti bütün məcburi dəyişənlərin təyin edildiyini yoxlayır. GitLab 2023-ə görə, .env.example istifadə edən komandalar mühit dəyişənləri ilə bağlı insidentlərin sayını 40% azaldır.
Üçüncü alət — pre-commit hookları. Hər commitdən əvvəl işə düşən avtomatik yoxlama: linter, formatlayıcı, tip yoxlaması, testlər. Hooklar bütün tərtibatçılarda eyni qurulubsa, „lokal maşında işləyən” formatlama və ya tip səhvləri istehsala çatmayacaq. JavaScript üçün Husky və Python üçün pre-commit — məşhur həllərdir.
Dördüncü — CI/CD boru xətti, testləri təmiz mühitdə işə salan. Testlər CI-də keçirsə, amma lokalda yox — problem lokal mühitin qurulmasındadır. Testlər CI-də keçmirsə — pull request birləşdirilmir. Bu sərt qayda „lokal işləyən” səhvlərin əsas budağa düşməsini istisna edir.
Tez-tez verilən suallar
Bu müdafiə reaksiyasıdır: tərtibatçı debug etməyə çox vaxt sərf edir və kodun işləmədiyini eşitmək psixoloji cəhətdən ağrılıdır. İfadə „keçid etmək” və günah hissi olmadan səbəbi axtarmağa başlamaq üçün vaxt verir.
Səhvi təmiz mühitdə (clean install, inkognito rejimi) təkrarlamağı xahiş edin. Əgər təkrarlanmırsa — asılılıqların versiyalarını və mühit dəyişənlərini müqayisə edin. Kömək etmirsə — istehsalla eyni Docker mühitini qaldırın.
Docker istənilən ƏS-də eyni işləyən izolyasiya edilmiş konteyner təmin edir. Bütün tərtibatçılar eyni Dockerfile-dan istifadə edir, buna görə də mühit eynidir. Əgər səhv konteynerdə təkrarlanmırsa — demək problem həqiqətən koddadır, sistemdə yox.
Lock-fayl bütün tranzitiv asılılıqların dəqiq heşlərini və versiyalarını təsbit edir. Paket reyestrində yeni versiya çıxsa belə, lock-fayl üzrə quraşdırma hər tərtibatçının qalanlarla eyni paket dəstini almasını təmin edir.
Vagrant VirtualBox ilə, əgər layihə ƏS nüvəsinin spesifik modullarından asılıdırsa və ya nüvə səviyyəsində tam izolyasiya tələb edirsə, əsaslandırılır. 90% layihələr üçün Docker daha yüngül, sürətli və rahatdır. Seçim layihənin ƏS ilə nə qədər dərindən qarşılıqlı əlaqədə olmasından asılıdır.
Nəticə
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