Makefile etkisine karşı dikkat uyarısı
(blog.yossarian.net)- Makefile etkisi, karmaşık ya da yabancı araçları sıfırdan kullanmak yerine, daha önce iyi çalışmış bir yapılandırmayı kopyalayıp yeni duruma göre değiştirme örüntüsünü ifade eder
- Sorun çözme aşamasında doğrulanmış örnekleri yeniden kullandığı için hata riskini azaltan rasyonel bir mühendislik tepkisi olabilir
- Ancak tasarım açısından bakıldığında, aracın en baştan kullanmasının zor ya da uğraştırıcı olması nedeniyle kopya üzerinde değişikliklerin durmadan biriktiğini gösteren bir kullanılabilirlik sinyali olarak görülebilir
- Benzer kopyala-düzenle akışı yalnızca Make'de değil, GitHub Actions, GitLab CI/CD, linter·formatter yapılandırmaları ve build sistemlerinde de ortaya çıkar
- Araç tasarımcıları, yapılandırma ve kendine özgü sözdiziminin gerçekten gerekli olup olmadığını, tanıdık CLI deyimlerinin yeniden kullanılıp kullanılamayacağını ve kullanıcıların kopyala-yapıştır bağımlısı hâline gelip gelmediğini kontrol etmelidir
Makefile etkisi nedir
- Makefile etkisi, belirli bir düzeyde karmaşıklık ya da yabancılık içeren bir araç için her şeyi yeniden yazmak yerine, daha önce “iyi çalışmış” bir örneği kopyalayıp değiştirme olgusudur
- Tipik akış şöyledir
- Yaygın bir iş türünün tamamlanması gerekir ve buna çok benzer ya da aynı iş daha önce zaten yapılmıştır
- Bu iş için uygun araç olarak Make ya da benzer bir araç seçilir
- Mühendis yeni bir
Makefileyazmak yerine önceki işinMakefiledosyasını kopyalar, ardından yeni ortamda çalışana kadar düzeltir
- Make yalnızca temsilî bir örnektir; ekip ya da kişiye göre ustalaşılan araçlar farklı olduğundan, bazı araç aileleri bu etkiye daha açıktır, bazıları ise görece daha az açıktır
- “heritage
Makefile” şakası, kıdemli mühendislerden, hocalardan vb. devralınan birMakefileın küçük değişikliklerle sürekli aktarılmasını ifade eder
Tekrarlanan kopyalamanın ortaya çıkardığı araç tasarımı sorunları
- Sorunun hemen çözülmesi gereken anda çalışan örneği yeniden kullanmak özlü bir tercih olabilir
- İşin büyük kısmı değişmediği için, teorik olarak daha az yeni hata üretilebilir
- Makefile etkisi özünde kötü ya da verimsiz bir olgu değildir
- Tasarım aşamasında ise araç ya da aracın uygulanma biçiminin fazla karmaşık veya zahmetli olduğuna işaret eder
- Kullanıcılar problemi sıfırdan çözmek yerine mevcut çözümü tekrar tekrar kopyalar
- Bu etki basit kullanım örneklerinde ortaya çıkıyorsa, araç o amaç için gereğinden fazla karmaşık olabilir
- Bu örüntü, Make dışındaki yapılandırma merkezli araçlarda da görülür
- CI/CD yapılandırmalarında, GitHub Actions ya da GitLab CI/CD YAML dosyaları en son çalışan yapılandırmadan kopyalanır ve tekrar tekrar çalıştırılıp düzeltilir
- Linter ve formatter yapılandırmaları, temel kural paketlerini projeler arasında kopyalar ve yerel koşullara göre sıkılaştırır ya da gevşetir
- Build sistemlerinin kayda değer yapılandırmaları, önceki build sistemlerine benzemeye eğilimlidir
Öğrenme, debugging ve güvenlikte oluşan maliyetler
- Makefile etkisinin güçlü olduğu araçlar, geniş kapsamlı öğrenmeyi engelleyebilir
- Az sayıda uzman aracı yapılandırır, geri kalanlar ise yalnızca ihtiyaç duydukları kısmı anlayarak kopyalayıp değiştirir
- Bir build sisteminin bağımlılık grafiği özsel bir karmaşıklıktır; ancak Make içinde
$<ile$^arasındaki farkı ezberlemek böyle değildir
- Tanılama ve debugging desteği zayıfsa, kullanıcılar aracı defalarca çalıştırıp yalnızca küçük ipuçları elde ettikleri bir yönteme bağımlı hâle gelir
- CI/CD'de ağ ve ara VM orkestrasyon katmanları üzerinden print tarzı debugging yapılır
- Güvenlik açısından da risk artabilir
- Güvenlik önlemleri çoğu zaman davranışın “neden”ini derinlemesine anlamayı gerektirir
- Makefile etkisinin görüldüğü sistemler, kod ve veri karışıklığına ya da genel in-band signaling karışıklığına sıkça izin verir
- GitHub Actions'taki template injection bunun tipik bir örneğidir
Araç tasarımcılarının sorması gereken sorular
- Yeni bir araç geliştirirken, kullanıcıların onu sıfırdan yazıp yazamayacağına yoksa mutlaka “çalışan bir örnek” bulup kopyalamak zorunda kalıp kalmayacağına bakılmalıdır
- Kontrol edilmesi gereken sorular şunlardır
- Yapılandırılabilirlik gerçekten gerekli mi
- Kendine özgü bir sözdizimi gerçekten şart mı
- Başka araçların ya da CLI'ların tanıdık sözdizimi ve deyimleri yeniden kullanılabilir mi
- Aracı yapan kişi bile kullanımını kopyala-yapıştır ile mi uyguluyor; öyleyse başka kullanıcıların da bunu yapma olasılığı var mı
- “cargo cult” terimi hakkında Ken Shirriff'in yazısı, bunun uygun olmayan bir uzmanlık jargonu olması sorununu ele alıyor
1 yorum
Hacker News yorumları
“Çalışan karmaşık bir sistemin, istisnasız olarak, çalışan basit bir sistemden evrilmiş olduğu görülür. Sıfırdan tasarlanmış karmaşık bir sistem asla çalışmaz; yamayıp çalışır hale de getiremezsiniz. Çalışan basit bir sistemle yeniden başlamanız gerekir.”
— John Gall (1975), Systemantics: How Systems Really Work and How They Fail
https://en.wikipedia.org/wiki/John_Gall_(author)#Gall's_law
Genelde özel durumları ele almak için çizik gibi özellikler eklenmeye başlar; bu da ileride bu tür istisnaların sonu gelmeden artacağının işareti gibi görünür.
“Deneyimi uygulamak” ile “kişisel olarak göze batan tek bir şeyin etrafında tamamen yeni bir sistem tasarlamak” arasında ince ama önemli bir fark vardır.
Başka bir varsayımım var. Geliştiricilerin yaklaşık %10’u gerçekten ilkeleri anlayıp bir şeyi sıfırdan başlatabilir; bir diğer %40’ı da yerel koddan, Stack Overflow’dan, GitHub’dan ve LLM’lerden kopyala-yapıştır yaparken kabaca ne olup bittiğini bilir ve günlük işleri halledebilir.
Kalan %50 ise birkaç LeetCode bulmacasının ötesini pek bilmez ve kopyalayıp yapıştırdıkları şeylere dair gerçek bir anlayıştan da yoksundur.
Dağılım böyleyse Makefile’ların yarısından fazlasının kabaca çalışan kopyala-yapıştır parçaları olma ihtimali yüksektir. Zaten çalıştığı bir yerden aldıysanız iş şimdilik biter ve sıradaki ticket’a geçilir.
Aracın kendisini suçlamıyorum. Makefile iyi bilinir ve küçük projelerde fazla laf kalabalığı da yapmaz. 10.000 dosyalık bir canavar için kötü bir seçim olabilir ama devasa projelerde bile temiz Makefile’lar gördüm. Kişisel olarak ilk tercihim olmazdı ama Makefile’ı seviyorum ve 30 yılı aşkın süredir ara ara kullanıyorum.
Örneğin bir C++ programcısı bir ticket üzerinde çalışırken yığının kaç katmanını bilmek zorunda? CPU register adlarına kadar bilmeli mi? Yalnızca Jupyter kullanan bir yapay zeka araştırmacısı nereye kadar bilmeli? Araçları ve stack’i olabildiğince öğrenmek tavsiye edilir ama zaman sınırlıdır.
Makefile’da tek bir dosyayı oluşturmak için ayrı bir kural görürsem bunun neredeyse her zaman hata olduğunu düşünürüm.
Normalde belirli bir türdeki tüm dosyaları build etmek için kullanılan yalnızca genel build kuralları olmalıdır.
Makefile’da kaynak dosya listeleri veya bağımlılık listeleri neredeyse hiç yer almamalı; yalnızca kaynak dosyaların bulunduğu dizinlerin listesi olmalıdır.
Make, kaynak dizinlerini tarayıp dosyaları bulmalı, türlerine göre sınıflandırmalı, bağımlılık listesini çıkarmalı ve uygun build kuralını çağırmalıdır. En azından GNU make’te bu çok basittir ve kullanıcı kılavuzunda da yer alır.
Böyle yazıldığında, proje ister 1 dosya ister 10.000 dosya olsun Makefile oluşturma veya düzenleme çabası aynı ölçüde ihmal edilebilir düzeyde kalır. Kaynak dosyalar oluşturulduğunda, yeniden adlandırıldığında, taşındığında veya silindiğinde Makefile’ı güncellemek de gerekmez.
Çünkü her dil ve framework için build “sırası” farklı ve hepsini hatırlayamıyorum. Ama
$ makekolay.Pek çok üretken uygulama geliştiricisinin yeni bir projeyi sıfırdan kuramayabileceğine katılıyorum; ancak bu çoğu zaman derin bir anlayıştan ziyade, çeşitli araçları doğru şekilde birbirine bağlayan sihirli kuralları ve büyülü komutları bilme meselesidir.
İş yerinde gördüğüm bir başka etken de geliştiricinin eninde sonunda uğraşmak zorunda kaldığı, ama normalde öğrenmeye değeri düşük gibi hissettiren araçlar ve sistemler
Örneğin build sistemleri ve CI yapılandırmaları. Kesinlikle gerekli, ama geliştiriciler bunlarla her gün uğraşmaları gerektiğini düşünmüyor. CI, “kur ve unut” türü bir sistem gibi görülüyor; bir uygulamayı build etmek için bunların hepsini öğrenmek zorunda mıyım tepkisi doğuyor
Geliştiriciler bunun “öylece çalışmasını” bekliyor; bir karmaşıklık varsa bunu başka bir ekibin, yani benim rolümdeki birinin, halledeceğini düşünüyorlar. Bu yüzden geliştirici bu sisteme her dokunduğunda, en son çalışan ayarı kopyalayıp devrederek “asıl” işine dönme motivasyonu çok güçlü oluyor
En iyi çözüm, geliştiricilerle yarı yolda buluşmak. İşe uygun şekilde basit ya da karmaşık araçlar sunmak, dokümantasyon sağlamak ve bunun “sihir” olduğu inancını en aza indirmek gerekiyor. Make gibi araçlar fazla karmaşık ve kara kutu gibi hissettirdiği için bu noktada genelde başarısız oluyor
Bu yüzden geri bildirim döngüsü aşırı uzuyor ve işin kendisi büyük bir eziyete dönüşüyor
Geliştirici “CI/CD” işinin bir kısmını ya da tamamını lokalde çalıştırabiliyorsa onu görebilir, kontrol edebilir ve anlayabilir. “CI/CD başka bir dünyanın işi” hissi yerine sahiplenme ve güven duygusu vermede çok yardımcı olur
Her zaman işe yaramaz. İki kişilik bir ekibin, ince wrapper’lı CI/CD’ye sahip olmasına rağmen ona uzaylı bir süreçmüş gibi davranıp dokunmayı reddettiğini görmüştüm
Benzer şekilde CI’ın bir sahipliği olmalı; sorumluluğun CI’ı en son kullanmaya çalışan geliştiriciye kalması verimli bir çalışma biçimi değil
Çözüm, sırf büyük şirketler kullanıyor diye büyük şirketlerin kullandığı araçları almamak. Popüler olmayacak bir görüş ama CI/CD’nin kullanıldığı yerlerin çoğunda gerekli olmadığını düşünüyorum
Adımlar biraz artsa bile, build ve dağıtım için hareketli parçaları mutlak minimumda tutmanın yolunu bulmak gerekir. Sonra hangi kısımların otomatikleştirileceğinin maliyeti dikkatle tartılmalı. Basit bir işi yapmak için büyük bir sistemi içeri almak uzun vadede genelde değerli değildir
Gerçekten CI/CD’ye ihtiyaç varsa bunu bir acı noktası olduğu için anlarsınız. O sistem geliştiriciye acı çektiriyorsa doğru araç değildir
make“fazla karmaşık ve kara kutu gibi” geliyorsacmakei henüz görmemişsiniz demektirMake ve Makefile, autoconf tarafından otomatik üretilmedikleri sürece son derece basittir. autoconf’un ürettiği bir şeyse değiştirmemelisiniz; o bir build çıktısıdır. Mümkünse autoconf’u da bırakmak iyi olur
Daha geniş bakınca bu etki gerçekten var. Buna yenik düşebilirsiniz de ondan yararlanabilirsiniz de. Yararlanma biçimi şöyle: Biraz kod yazarsınız ya da bir yerden kopyalayıp yapıştırırsınız, projede kullanırsınız, ihtiyaca göre düzeltirsiniz. Sonraki projeye başlarken o kodu yeniden kopyalar, ikinci projeye uyacak şekilde değiştirirsiniz. Değişiklikleri ilk projeye de geri uygulayıp uygulayamayacağınıza bakarsınız. İkisi de çalışıyor ve senkron kalıyorsa o kodu çıkarıp kütüphane yaparsınız. Bazen kütüphane formuna rafine etmek için daha fazla proje gerekir. En iyi durumda açık kaynak olarak yayımlayıp başkalarının da kullanmasını sağlarsınız
Git içsel olarak zaman damgası kaydetmediği için içerik aynı olsa bile dosyanın mtime’ı güncellenebilir; pratikte de sık sık böyle olur ve gereksiz yeniden build’lere yol açar
Girdisi veya çıktısı tüm bir dizin olan modern araçları ya da çalışmadan önce çıktı adlarını bilemeyen araçları da hiç doğru düzgün ele alamaz
make’i seviyorum, eksiklerine rağmen iyi kullandım; workaround’ları ve o workaround’ların workaround’larını da biliyorum. Ama araçlar make’in beklentileriyle kusursuz örtüşmemeye başladığında doğru Makefile yazmanın zorluğu ve karmaşıklığı hızla fırlar
Şaka değil.
make cleandiye bir kavramın var olması bile kesin kanıttırMakefile muhtemelen yanlış bir benzetme olabilir. Çoğu kişinin Makefile’da yaşadığı sorun, onu çok nadiren yazmasından kaynaklanıyor. make’in ne yaptığına dair genel bir sezgi var, ama sıfırdan yazmaya yönelik kas hafızası yok
Yine de ana fikir doğru. Web’den kopyalanmış kodlarda gerçekte kullanılmayan bir sürü ölü kodun kaldığını çok gördüm. İyi alışkanlık, bozulana kadar silmeye devam edip yalnızca bozulan kısmı geri almaktır. Mümkün olduğunca çok silmeli ve şu anda kullanılmayan her şeyi kesinlikle kaldırmalısınız
Şimdiye kadarki çözümüm, bu tür araçlar, kütüphaneler ve framework’ler hakkında notlar ile shell script örnek programlarını topladığım ayrı bir depo oluşturmaktı
Aracı yeniden kullanmam gerektiğinde notlara bakıp hafızamı tazeliyorum; yeni bir şey öğrendiysem notları güncelliyorum. Artık LLM’ye o depoyu gösterip soru da sorabiliyorum
Bu depo kişisel ve herkese açık bulunabilen araçlar hakkında bilgiler içeriyor. Kuruma özgü bilgi ise benzer ama ayrı bir depoda tutuluyor; müşteri ya da işverenle sözleşme bitince de imha ediliyor
Buna en iyi verilecek ad kargo kültü geliştirme. Kargo kültü, II. Dünya Savaşı sırasında Pasifik’te ortaya çıktı; yerli ada halklarının yiyecek, içki ve malzeme taşıyan mucizevi uçakları görüp, askerlerin yaptıklarını taklit ederek bambudan uçaklar ve hindistan cevizinden düzeneklerle tanrıları etkileyip malzemelerin yeniden gelmesi için dua etmelerinden doğdu
Sorun, ada halklarının uçak, telsiz, silah gibi şeylerin bilimini anlamamış olmasıydı
Benzer şekilde kargo kültü tarzı geliştirici olası sonucu görür ama ilk ilkeleri anlamaz; teknolojinin yüksek rahiplerinin yaptıklarını taklit ederek başarıyı kopyalayabileceğini umar
Böylece kopyala, yapıştır, dene, kurcala, ara, çek, it, ayarla döngüsünü tekrarlayıp bu kez en azından salı akşamındaki belirli verilerde aşağı yukarı çalışmasını uman bir hale gelir
Aslında kendi başına etkisi olmayan hareketleri ya da ritüelleri tekrarlayıp, aynı ritüelleri yapan başka bir şirketin elde ettiği sonucu beklemektir
Orijinal yazıda söylenen şey farklı. Kopyalanan nesne olan kodun kendi başına bir etkisi var. Test edip çalışıp çalışmadığına karar verebilirsin
Bu ayrım önemli. Orijinal yazıdaki Makefile etkisiyle kargo kültünün belirtileri farklı olduğundan, ikisini aynı şeymiş gibi ele almak teşhisi zorlaştırır. Kargo kültünde batıl inanç yüzünden gerçekten çalışmayan şeylere zaman harcanır. Makefile etkisinde ise çalıştığı kanıtlanır, ama körelmiş organ benzeri parçalar da kopyalandıkça bakım giderek zorlaşır
Daha somut olarak, bunun kargo kültüyle birebir aynı olduğunu düşünmüyorum. Kargo kültü anlama eksikliğini ima eder. Ama bir sistemi iyi anlasan bile, o sistemin içsel karmaşıklığı kopyala-yapıştırı teşvik ettiği için çoğunlukla böyle yaşayabilirsin. Yazının ana noktası buydu
Genelde içeride ne olup bittiğini anlıyorum, ama o “mod”a geçmenin kendisi bilişsel olarak ağır geldiği için mümkünse kaçınıyorum
Buna giren araçlar arasında CI/CD, k8s, Docker gibi karmaşıklığı çok yüksek ama çözdüğüm asıl sorun olmayan operasyon tarafı araçları çok. Make ise bağlam değiştirmeyi özellikle zorlaştırdığı için bugünlerde ondan doğrudan kaçınma eğilimindeyim
Bunun sihirli büyülerle ilgisi yok; yaptığım ödünleşimin farkındayım. Yine de Makefile etkisine dönüşme riski var
“Makefile etkisi; kargo kültü, sapmanın normalleşmesi, ‘yalnızca yazılan dil’ gibi başka olgulara benzer. Bu yazıda bunun özünde verimsiz ya da kötü olmadığını, belirli bir tasarımın sonuçlarını ele alması bakımından her birinden biraz farklı olduğunu savunacağım”
O zaman biri gerçekten “adadan kaçıp uçağı kullanmak” istiyorsa, sonuçta üniversite “gerçeğe” en yakın yol mu demek oluyor?
Mutlak konuşmanın zor olduğunu, çok sayıda istisna bulunduğunu ve herkesin “ben onu yapamam” demek için farklı gerekçeleri olduğunu biliyorum. Burada optimum teori açısından soruyorum. Kültvari davranıştan kaçınmanın en iyi yolu bütünü anlamaktır; o “bütün” de yükseköğretimden gelmez mi?
Mantıken, kitaplarla ciddi biçimde çalışarak üniversitenin “eksiksizliğini” yakalamaya ya da aşmaya çalışsan bile, bilgili bir eğitmenle sınıfta geçirilen zamana kıyasla bazı yönlerden eksik kalacak gibi görünüyor. Aynı kişinin her iki yolda da aynı derecede çok çalıştığını varsaysak bile
Bir başka etken de kullanım sıklığı. LaTeX ile uzun bir metin yazmam yılda bir kezden az oluyor
Benim kullandığım düzeyde LaTeX zor bir araç değil, ama yılda yalnızca birkaç hafta kullanınca kullanım ayrıntılarını asla hatırlayamıyorum; bu yüzden genelde önceki belgeleri kopyalayıp yapıştırarak yeni bir belgeye başlıyorum
Ama LaTeX’i eskiden çok fazla kullanmış olmama rağmen hep şablondan kopyalayıp yapıştırdım. beamer sunuları ve TikZ çizimleri daha da beterdi; şablondan değil, önceki sunu ya da çizimlerden kopyalıyordum
TikZ için aracın kendisinin özünde karmaşık olduğunu ve benim yeterince öğrenmediğimi düşünüyorum
LaTeX’i ise yeterince öğrendiğimi düşünüyorum; dolayısıyla başka bir neden olabilir
Bence bu makul varsayılanlar meselesi olabilir. İyi bir araç iyi varsayılanlar sunmalıdır. Ama LaTeX bu ölçüte göre iyi bir araç değil. Belgelerim genelde şöyle başlıyor Bunların çoğu ana dilim için gerekli temel ASCII dışı desteği almak ya da A4 kâğıt, microtype gibi makul varsayılanları açmak için. pandoc/Markdown gibi modern araçlarda bunlar gerekmeyebilir
Bu yüzden böyle şeyleri kopyalayıp yapıştırmanın amacı çoğu zaman, daha iyi bir aracın en baştan sunacağı iyi varsayılanları elde etmektir
Matematik yazmıyorsan ya da yalnızca İngilizce düz metin yazmıyorsan LaTeX neredeyse “piller dahil değil” gibidir
Bu kopyala-yapıştır güdümlü geliştirme [0] ve sadece Makefile ile ilgili bir mesele de değil. Tüm sektörün neyi kopyaladığını bile bilmeden kodu oradan oraya kopyalamasıyla ilgili.
Açıkçası Copilot’ın bunu daha da kötüleştirdiğini düşünüyorum. Çünkü kod tabanına kod parçaları gözleri kapalı kabul ediliyor.
[0] https://andrew.grahamyooll.com/blog/copy-pasta-driven-develo...
makeuzmanı olmaya herhâlde en az 7 kez arka arkaya denedim ama tamamen ezberleyene kadar her gün uğraşacak zamanı hiç alamadım.Bir noktada sadece vazgeçtim. Kas hafızası oluşturamıyorsunuz ve ihtiyaç duyduğunuz her seferinde sıfırdan yeniden öğrenmeniz gereken anlaşılması güç, ezoterik bir bilgiye dönüşüyor. Bu yüzden daha basit araçlara geçtim.
Derin çalışmanın kaybı iyi programcıların değil, iş tarafındaki insanların suçu.
Başka bir projeden Makefile’ı olduğu gibi kopyalayıp “çalışır” hâle getirirken, tamamen alakasız ve gereksiz derleme adımlarını ve hedefleri olduğu gibi bırakan çok fazla örnek gördüm.
Şahsen beni ciddi şekilde rahatsız eden bir şey.
Deneme yanılmayla mı? O zaman iyi eğlenceler :p
Gereğinden fazla karmaşık çok araç olduğu doğru, ama Make’in kendisinin buna uygun bir örnek olduğunu düşünmüyorum.
Modern araçlarda karmaşıklık sorunu çoğu zaman eksik dokümantasyon, tarif kitabı tarzı dokümantasyon, aracın nasıl çalıştığını akıl yürütmek için gereken kavramsal modeli açıklamayan dokümantasyon ve yeterince ayrıntılı, doğru bir belirtimin bulunmaması yüzünden daha da kötüleşiyor.
Make böyle değil. Dokümantasyonu iyi ve gerçekten dokümanı okumaya zaman ayırırsanız anlaması zor değil.
Yukarıdaki tarif kitabı yaklaşımı, kullanılan aracı öğrenip anlamanın ve bunu mümkün kılan kapsamlı dokümantasyonun önemini küçümseyen bir kültüre yol açıyor. Ya da nedensellik ters yönde de olabilir.
Her hâlükârda bence sorun, kapsamlı ve güncel araç dokümantasyonu hazırlamaya çok az zaman ayrılmasında; en başta böyle bir dokümantasyonu mümkün kılacak şekilde araç tasarlamaya da yeterince önem verilmemesinde ve gerekli araçları öğretip öğrenmeye çok az kaynak ayrılmasında.