Clean Code Prensipleri
CLEAN CODE-1
Kariyerime ilk başladığım şirkette ufak bir ekiple büyük ölçekli bir CMS uygulamasında geliştirmeler yapıyorduk. O zamanlar okulda ve kendi yaptığım projelerde öğrendiklerimin dışında ilk defa büyük ölçekli profesyonel bir projede kod yazıyordum. 1. senemin sonlarına geldiğimde ilk zamanlar geliştirdiğim kodlara geri dönüp baktığımda gözlerim kanıyordu 🙂 böylece sektördeki ilk teknik borçlanmalarımın geri ödemesini yapmaya karar verdim. Bu süreçte literatürü de biraz araştırıp clean code standartlarını öğrenmeye karar verdim ve sizlerin de incelemek isteyebileceği iki güzel ile birlikte görebildiklerimi ve faydalandıklarımı paylaşmak istedim.
Pluralsight üyeliği olanlar için Clean Code: Writing Code for Human
Kitap karıştırmayı sevenler için Clean Code A Handbook of Agile Software Craftsmanship
İşi biraz daha ileri taşıman isteyenler de Clean Architecture kitabına da bakabilirler.
Konuya Clean Code A Handbook of Agile Software Craftsmanship kitabının girişinden çok hoşuma giden, clean codingin önemini anlatan bir yazıyla başlayayım.
80’lerde bir şirket müthiş ve çok popüler bir uygulama yazdı. Ancak bir zaman sonra yeni sürüm çıkma (release) dönemleri uzamaya başladı. Bir sonraki sürümde hatalar çözülmemiş oluyordu. Yüklenme süresi uzuyor ve çökmeler artıyordu. Büyük bir hüsran ile uygulamayı kaldırdığım günü hatırlıyorum. Zaten bir zaman sonra da şirket tamamen piyasadan çekildi.
20 yıl sonra şirketin ilk çalışanlarından biri ile karşılaştım ve ona ne olduğunu sordum. Cevabı korkularımı doğruladı. Ürünü markete erkenden sürebilmek için çok acele etmiş ve kodda çok büyük bir kargaşaya sebep olmuşlardı. Daha fazla özellik ekledikçe, kod daha da kötü bir hal almış ve o kadar kötü hale gelmişti ki, artık kodu yönetemiyorlardı. Böylece kötü kod şirketin kapanmasına sebep olmuştu.
Hepimiz zaman zaman geri dönüp kodumuzu temize çekeceğimizi söylemişizdir. Ancak o zamanlar LeBlanc’ın şu kuralını bilmiyorduk: “Sonra asla demektir (Later equals never).”
Kod karmaşıklığı arttıkça takımların verimliliği düşer ve sıfıra yaklaşır. Verimlilik düştükçe de yöneticiler yapabildikleri tek şeyi yaparlar; verimliliği artırması umudu ile projeye daha çok insan kaynağı eklerler. (İnsan kaynak mıdır yoksa değer mi?) Takımdaki herkes verimliliği artırmak için büyük baskı altındadır. Öyle ki verimliliği sıfıra daha da yaklaştıracak şekilde kod karmaşası yaratmaya devam ederler.
Bu kısa anlamlı hikayeden sonra clean kodun çekirdek prensiplerine geçebiliriz diye düşünüyorum. Bu yazımda belli kaynaklardan ve deneyimlerimden derlediğim, kod yazarken ufak dokunuşlarla kodu daha temiz ve okunulabilir kılmak adına bazı yöntemlerden bahsetmeye çalışacağım.
1. Sınırları belirleme
Ölçeği büyük projeler geliştirirken javascript, html, css, C#, sql gibi bir çok teknololojiyi bir arada kullanmamız gerekebilir. Ancak bu teknolojilerin her birinin söz dizimi ve yapısı farklıdır. Bu sebeple kullandığımız teknolojilerin sınırlarını belirlememiz gerekir. Bu da bize daha okunaklı, bakıma ve geliştirmeye açık kod yazma imkanı sunar.
Eğer ki bir projede javascript, html, css, C#, sql gibi teknolojileri bir arada kullanıyorsak, dikkat etmemiz gereken nokta, her teknolojinin kendisine ait uzantılı dosyada tutulması gerektiğidir. Javascriptlerimiz .js uzantılı, csslerimiz .css uzantılı, htmller .html uzantılı, C# kodları .cs uzantılı dosyalarda ve sql kodları da uygun bir yapıda soyutlanmış olmalıdır.
2. İsimlendirme
İsimlendirme konusu kulağa çok basit bir konu gibi gelse de yazılım geliştirmenin en önemli noktalarındandır. Anlamsız veya kısaltmalarla verilen isimler bir süre sonra kodun okunurluğunu azaltarak kodu anlayacak kişiye zaman maliyeti olarak dönecektir. Aynı şekilde anlamlı ve doğru verilen isimler yazılımcının işini inanılmaz derecede kolaylaştırabilir. Normal şartlarda, bir fonksiyonu ismiyle değişkenleriyle yapılan işlemleri vs ile yukardan aşağıya bir kitap okur gibi okuyup anlamlandırabiliyor olmamız gerekir. Bu tip kodlar yorum satırlarına da nadir olarak ihtiyaç duyarlar ve self-documented kod olarak isimlendirilirler.
2.a Class İsimlendirmeleri
Tanımlayacağınız classın single responsibilty prensibine uygun olması ve isminin de bu single responsibility’i net bir biçimde yansıtıyor olması gerekir. İyi isimlendirilmiş classlar genelde isim olarak bir fiil değil bir isim alırlar. Classlar, nesnelerini üretebildiğimiz yapılar olduğundan bir class isimlendirirken kendinize sormanız gereken soru, bunun nesnesini üretmek OOP’ye göre kulağa mantıklı geliyor mu? olmalıdır.
Dirty Clean WebsSiteBO User Utilty Account Common QueryBuilder MyFunctions ProductRepository JimmysObjects Manager, Processor,Info
2.b Method İsimlendirmeleri
Kötü bir metot isimlendirmesi okunduğu zaman, metodun ne iş yaptığına dair kafa karışıklığı yaratır. İyi isimlendirilmiş metodun ismini okunduğunda da metodun gövdesini dahi okumadan ne iş yaptığı anlaşılır ve kullanılabilir. Metotlar bir fonksiyonelliği yerine getirdiklerinden isimleri ‘fiil’ olmalıdır.
Metotlar da classlar gibi single responsibilty prensibine uymalı ve sadece tek bir fonksiyonelliği yerine getirmelidir. Metot isimlendirmesinde And, If, Or, gibi bağlaçlar geçiyorsa orada durup metot birden fazla işi içerisinde barındırıyor mu diye bir düşünmeniz gerekli.
Dirty Clean Getprocess GetRegisteredUsers pending IsValidSubmission dolt ImportDocument start SendEmail On_init SaveAndPublish
3.b Kısaltma kullanımı
İsimlendirmelerde kısaltma kullanımı kodlamada yapılan en büyük yanlışlardandır. Bir geliştiricinin yazdığı kodu başka bir geliştirici okurken kitap okur gibi ne yazıldığını anlayabilmelidir. Burdan yola çıkarak kitap okurken, kitaptaki isimlerin kendilerini değil de kısaltmalarını görseniz sizin için de çok anlamlı olmazdı.
Dirty : regUser, registUser, RegisUser..
4.b Boolean isimlendirmeleri
İyi bir boolean isimlendirmesi okuyucuya sanki cevabı “doğru” veya “yanlış” olan bir soru soruyormuş gibi olmalıdır.
Dirty Clean open IsOpen start done status isActive login loggedIn
3. Conditionlar
- Booelan bir değeri condition içerisinde tekrar true ya da false’a eşitlemek gerek olmayan bir kalabalık yaratacaktır onun yerine aşağıdaki kullanımı tercih etmeliyiz.
Dirty Clean if(loggedIn==true) if(loggedIn) {} {}
- Boolean değişkenlere true false atamalarında dikkat etmemiz gereken nokta, elimizdeki değişkene sonucu aşağıdaki gibi direkt olarak bu boolean üzerinden atayabiliriz. Böylece aşağıda olduğu gibi 8-9 satırlık kodu tek satırda yazabiliriz.
Dirty bool goingToChipotleForLunch; if(cashInWallet>60) Clean { goingToChipotleForLunch=true; bool goingToChipotleForLunch = cashInWallet>6.00 } else { goingToChipotleForLunch=false; }
int regisrationFee; if(isSpeaker) int registrationFee = isSpeaker ? 0 : 50; { registrationFee=0;} else {registrationFee = 50;}
- Koşul cümlelerinde ters koşul kullanmak da kodu okuyanlar için kafa karışıklığı yaratmaktadır. Elimizden geldiğince pozitif anlamlı koşullar üzerinden ilerlemeliyiz.
Dirty Clean if(!isNotLoggedIn) if(loggedIn)
- Bir grup seçenek arasından seçim yapacaksak bunu static olarak vermektense enumlara bağlayıp kullanmak daha yerinde olacaktır. Böyleyce kodda ilgili bir opsiyonu değiştirmek istediğimizde, o opsiyonun kullanıldığı yerleri tek tek bulup değiştirmek yerine, ilgili enum opsiyonunu değiştirmemiz yeterli olacaktır.
Dirty Clean if(employee=="Manager") if(Employee == EmpoyeeType.Manager)
- Kodun içerisinde hiç bir anlam ifade etmeyen sayı, string gibi staticleri de direkt olarak kullanmamamız gerekir. Aşağıda age > 21 koşulu bize yaşın 21’den büyük olması durumunu net bir şekilde anlatıyor ancak 21’in ne ifade ettiği ve neden orada olduğu konusunda bir fikrimiz yok. Değişken çok yerde kullanılıp belli aralıklarla değiştirilmeyecek ise database’de tutmak yerine aşağıdaki şekilde bir tanımlama koda anlam katacaktır.
Dirty Clean if(age>21) int legalDrinkingAge=21; if(age>legalDrinkingAge)
- Kompleks koşullar okunurken kafa karışıklığı yaratır. Örneğin aşağıdaki gibi bir koşulun hem takip edilmesi hem de ne amaçla oraya konulduğunu anlamak oldukça zordur. Ancak unutmamamız gereken şey, her boolean ifade ve bunu içerisinde barındıran her koşul aslında cevabı true ya da false olan bir soruya cevap verdiğidir ve bu sorunun cevabına göre koşul değerlendirilir. Bunu göz önünde bulundurarak elimizdeki kompleks koşulların hangi soruya cevap verdiğine istinaden bir değişkene atamamız veya fonksiyonlaştırmamız işimizi oldukça kolaylaştıracaktır.
Dirty if(employee.Age>55 && empoyee.YearsEmployed>10 & employee.IsRetired==true) Clean bool eligibleForRetirement= employee.Age > minRetirementAge && employee.YearsEmployed > MinPensionEmployementYears && employee.IsRetired; if( eligibleForRetirement )
veya
Dirty if(fileExtension=="mp4" || fileExtension =="mpg" || fileExtension == "avi") Clean private bool ValidFileRequest(string fileEtension) { return (fileExtenion=="mp4" || fileExtenion=="mpg" || fileExtension=="avi"); } if( ValidFileRequest(fileExtension) )
- Yazılımcılar olarak kodları çok sevsek de bazen her şeyin cevabı kod olmayabiliyor. Elimizde, belli değerlere karşı belli sonuç döndüren bir yapı olduğunu varsayalım. Bunu hard-coded olarak kod içerisinde tutmaktansa, database’de bir tabloda json formatında veya key value şeklinde tutup ilgili key’e ilgili value’yi dönen bir fonksiyon üzerinden yürüyebiliriz.
Dirty if(age<20) return 345; else if(age<30) Clean return 419; return Repository.GetInsuranceRate(age); else if(age<40) return 476; else if(age<50) return 516;
- Validasyonları iç içe if kullanarak yapmak çoğu yazılımcının düştüğü bir yazım yanlışıdır. Bu şekilde bir validasyon zincirinin okunması ve aynı zamanda hangi ifin hangi else denk geldiğinin anlaşılması zordur. Bunun yerine ifleri alt alta sıralayıp ilk yakalanan validasyondan itibaren kodu return etmek daha doğrudur.
Dirty Clean if() if() if() return; if() if() return; if() if() return; do something... if() return; else do something... return; else return; else return; else return;
4. Fonksiyonlar
4.a Kod tekrarından kurtulmak
Dry(dont repeat yourself) çoğu yazılımcının duyduğu bir kod prensibidir. Bir fonksiyonelliği kodun birden fazla kısmında tekrar eden bir şekilde yazdıysanız ve daha da kullanmaya ihtiyaç duyabileceğiniz potansiyelde bir kod ise bu kod parçacığını metotlaştırmalısınız demektir.
4.b Olabildiğince Küçük..
Fonksiyon yazarken göz önünde bulundurmamız gereken en önemli kriterlerden birisi fonksiyonların olabildiğince küçük olmasıdır. Bir fonksiyon 100’lerce satırdan oluşmamalıdır en fazla 20 satırda fonksiyonu tamamlarsanız tadından yenmez. Eğer fonksiyonunuz satır sayısı gitgide artıyorsa ve siz de hala yazmaya devam ediyorsanız, orada durup bu fonksiyonu daha küçük parçalara nasıl ayırırım diye bir düşünün derim 🙂
4.c Yalnızca tek işlev
Her fonksiyon yalnızca bir işlevselliği gerçekleştirmeli ve bunu da en efektif şekilde gerçekleştirmelidir. Fonksiyonu yazan yazılımcı da onu ileride çağıracak olan yazılımcı da o fonksiyonu tek ve spesifik bir amaç için çağırmalıdır ki bu da fonksiyonun isminden net bir şekilde anlaşılabilmelidir. Sonuçta önceden yazılmış bir fonksiyonu kullanırken tekrar tekrar kodlarını kontrol edemeyiz ve kimse adından yola çıkarak çağırdığı bir fonksiyonun arkada öngöremeyeceği hareketler yapmasını istemez 🙂
4.d Niyeti net bir şekilde belli etmek
Koşul ifadelerinin içerisindeki koşulları programatik olarak çoğu zaman anlarız ancak neden o şekilde yazıldığını altında yatan anlamı tam olarak anlayamayız. Örnek üzerinden ilerlersek aşağıdaki kirli kod örneğinde koşul yapısı bize fileExtension’un mp4, mpg veya avi olması gerekiğini ve isAdmin veya isActive’İn true olması gerektiği net bir şekilde gösteriyor ancak hem bu ifadelerin altında yatan anlamı tam olarak göstermiyor hem de kodu okuyan geliştiricinin işini zorlaştırıyor.
Dirty if(fileExtension == "mp4" || fileExtension =="mpg" || fileExtension =="avi" && (isAdmin || isActive))
Aşağıdaki kod örneği ise koşul yapısının amacını net olarak belli eden ve geliştiricinin rahatlıkla okuyup anlayabileceği kod örneğidir.
Clean private bool ValidFileRequest(string fileExtension, bool isActiveFail, bool isActive) { var validFileExtensions = new List<string>() {"mp4","mpg","avi"}; bool IsValidFileType = validFileExtensions.Contains(fileExtension); bool IsUserAllowedToViewFile = isActiveFile || isAdmin; return IsvalidFileType && IsuserAllowedToViewFile; } if(ValidFileRequest(fileExtension, active))
- Clean kod yazarken kullandığımız dilin bize verdiği nimetlerden de yararlanmalıyız. Örneğin aşağıdaki iki kod parçacığı da aynı işi yapmakta ancak ilk kodun 5 satırda yaptığını ikinci kod tek satırda yapmakta ve ne yapmak istediği de çok net bir şekilde anlaşılabilmektedir.
Dirty List<User> mathcingUsers = new List<User>(); foreach(var user in users) { if(user.AccountBalanceStatus == Status.Active) { matchingUsers.Add(user);} } return matchingUser; Clean return users.Where(u=> u.AccountBalance < mininmumAccountBalance && u.Status == Status.Active);
4.e Parametre sayısı
Bir fonksiyonda çok fazla parametre olması sıkıntılı bir durumun işaretçisi olmakla birlikte fonksiyonun yapması gerekenden fazla iş yaptığının da habercisi olabilir. Fonksiyon yazarken parametre sayısını mümkün oldukça 0-2 arasında tutmaya gayret etmeliyiz.
Aşağıdaki kirli kod örneğinde metot fazla parametre almış ve User tipinde bir user, email gönderilip gönderilmeyeceğini belirleyecek olan bool bir sendEmail parametresi, emailFormatı, rapor yazdırılıp yazdırılmayacağını belireyecek olan bool printReport ve işin faturalandırılıp faturalandırılmayacağını belirleyen bool sendBill parametresi. Parametrelere bakıldığında dahi metodun yapması gerekenden daha fazla iş yaptığı rahatlıkla anlaşılmaktadır.
Dirty public void SaveUser(User user, bool sendEmail, int emailFormat, bool printReport, bool sendBill)
Boolean parametreler flag argument olarak değerlendirilir. Genelde fonksiyonun birden fazla iş yaptığını belirtir.
Aşağıda fonkisyonun aldığı iki parametreden yapması gerekenden fazla iş yaptığı anlaşılmaktadır. SaveUser metodu kaydedeceği kullanıcıyı almakta, bool emailUser ise bu user kaydedildikten sonra email atılıp atılmayacağını belirlemektedir. Email atma işi kullanıcıyı kaydetme işinden farklı bir iş olup farklı bir fonksiyonda farklı bir çağırımla gerçekleştirilmeli ve single responsibilty prensibine uyulmalıdır.(Side effect)
Dirty private void SaveUser(User user, bool emailUser) { if(emailUser) { yolla } } Clean private void SaveUser(User user) { //save user } private void EmailUser() { //email user }
5. Exception Handling
- Tanımladığınız exceptionlar, hatanın yeri ve kaynağı hakkında detaylı bilgi içermelidir. Bunun için exceptionlarımıza ve loglarımıza açıklayıcı hata mesajları eklemeliyiz.
- Hataları yutmamalısınız. 1 sene kadar önce çalıştığım şirkette geliştirilen bir uygulama ilk 2 3 hafta kusursuz çalıştı. Bu süre boyunca ufak bir hata bile vermedi. Tabi ekipte uygulamayı yazan kişiye takdirler tebrikler de havada uçuştu 🙂 . Bir noktada verileri kontrol edince tamamen tutarsızlıklarla dolu olduğunu gördük. Kodu açıp baktığımızda gördüğümüz şey bizim için sürpriz olmuştu. Tüm fonksiyonlar try catch içerisinde ve olası tüm hatalar loglanmadan ve bir uyarı verilmeden yutulmuş 🙂 . Error handling yaparken hataları yutmamaya özen gösterin. Exceptionu fırlatın fırlatın ki hata olduğunda anında o hata hissedilip çözülsün. Loglamayı da unutmayın tabi 🙂
- Try-catch ile exception yönetirken eğer try blogunun içerisi çok fazla büyüdüyse ve tryın kapsadığı kod parçası ilk bakışta try ile beraber ele alınamıyorsa, kod parçacığını fonksiyon haline getirip fonksiyonu try içerisinden çağırmak daha uygun olacaktır.
Dirty Clean try try { { // // saveThePlanet(); // // }catch // { } catch(ArgumentOutOfRangeException) // do something { } // do something }
6. Classlar
Olabildiğince küçük..
Classlar da tasarlanırken aynı fonksiyonlar gibi olabildiğince küçük olmalıdır. Fonksiyon yazarken bu küçüklüğü satır sayısıyla ölçebilirken classlarda ise sorumluluklar ile ölçebiliriz. Bir class sorumluluğunun dışında işler yapan fonksiyonları barındırmamalıdır ve bu sorumluluklar da olabildiğince daha ufak alt sorumluluk başlıklarına ayrılmalıdır.
Classların sorumluluk kısıtlarını yaparken en kolay kopya çekebileceğimiz yer ilk kısımlarda da bahsettiğim gibi, classın ismidir. Classınızı isimledirirken kısa, sade ve anlaşılır bir isim bulamıyorsanız classınızın içerisinde çok fazla sorumluluk ve ayrı tellerden çalan fonksiyonlar olabilir ya da class isminiz mantık olarak nesnesi üretilebilecek bir kavram değilse ve çok genel bir isim ise aynı şeyi söyleyebiliriz.
Bir kitapta okuduğum bir tanımda class sorumluluk kapsamı için şöyle bir cümle dikkatimi çekmişti.
Bir classın ne amaçla yazıldığını ve ne iş yaptığını “eğer, ve, veya, ama” kullanmadan 25 kelimede anlatabiliyor olmalısınız. 🙂
- Class nesnesi tanımlarken kod okunurluğunu artırmak için aşağıdaki gibi bir tanımlama daha uygun olacaktır.
Dirty Clean Worker worker = new Worker(); Worker worker = new Worker worker.Name= "Sam"; { worker.Surname="Brown"; Name= "Sam", worker.Age=21; Surname="Brown", worker.Title="Engineer"; Age=21, Title="Engineer" };
7. Commentler
İyi yerleştirilmiş bir yorum satırı okuyucu için çok faydalı olabilecek iken kötü ve düşünülmeden yazılmış yorum satırları kodu bir çöplük haline getirebilir. Çünkü yorum satırlarının %90’ının dayandığı sebep bellidir. Kötü kodu perdelemek. Kötü ve ne yaptığı belli olmayan fonksiyon ve kod parçacıklarını açıklamak için yorum satırı yazmaya yöneliriz. Bu da kod için oldukça tehlikeli bir durumdur. Neden yorum satırları kod açısından bu kadar sıkıntılıdır derseniz, yorum satırları genelde yalan söyler. Kod değişir ve gelişir ancak yorum satırları maintain edilmez. Yorum satırı yazmaya harcadığımız zamanı kodu temizlemeye harcarsak daha doğru bir yatırım yapmış oluruz 🙂 Yorum satırını da artık kodun yetersiz kaldığını düşündüğümüz durumlarda kullanmalıyız.
- Gereksiz yorum
int i=1; //sets i 1
- Niyeti belli etmeye çalışan yorum
Dirty Clean
if(isActive==2) // be sure that is active if(isActive == Status.Active)
- Zombie kod, kullanılmayan kod parçacklarının yorum satırı haline alınıp kod içesinde tutulmasıdır ki diğer developerlar tarafından fazlaca kafa karışıklığına yol açar. Developerin kafasında yorum satırındaki kod neden vardı? , yanlışlıkla mı yoruma alındı da unutuldu?, kim yaptı?, niye yaptı?, ileride bu koda ihtiyaç olucak mı yoksa artık tamamen işlevsiz mi? gibi sorular oluşturarak kafa karışıklığı yaratır ve okunurluğu azaltır.
8. Appendix
8.a Malfly variables
Yazılımla tanıştığım zamanlarda kod yazmaya başladığımda ilk yaptığım kod boyunca kullandığım ne kadar değişken varsa kodun başında tanımlamak ve sonrada gerek duydukça bunları kullanmaktı 🙂 . Ancak tüm yazı boyunca dediğimiz gibi, kodu okurken bir kitabı okuyormuş gibi yukarıdan aşağıya okuyup anlamlandırabilmeliyiz. Hiç kitabı okurken kitapta geçecek olan karakterlerin hepsinin ilk sayfada verildiğine tanıklık ettiniz mi? Kitapta karakterler ne zaman hikayeye giriş yaparsa o zaman adı geçmeye başlar. Biz de kod yazarken tanımlayacağımız değişkenleri fonksiyonun başında değil de ne zaman o değişkenin kullanımına ihtiyaç olduysa o zaman tanımlamalıyız.
Değişkenleri tanımlarken en kısa lifetime’a sahip olacak şekilde tanımlama yapmalıyız.
8.b Settingler
Kod yazarken hiç bir setting hard-coded olarak kodun içerisinde yer almamalı. Kodun içerisinde yer alan settingler için her bir setting değişikliği istendiğinde yeni bir geliştirme, deploy ve live’a çıkış anlamına gelir. Db’de tutulan settingler için ise istenen her değişiklik dbye atılan bir sorgu ile halledilebilir kod dışarıdan yönetilebilir olur.
Follow along with Robert “Uncle Bob” Martin and Justin Martin as they apply the principles learned in the Clean Code series to write an iPhone app in Swift.
Güzel
Ellerinize saglik. Güzel yazı olmuş.
Merhaba,
Emeğinize sağlık güzel bir paylaşım olmuş.
Validation lar ile ilgili duruma katılmakla birlikte; her kontrol sonrasında return yerine tüm validationların yapılıp tek bir return ile dönüş yapılması daha anlamlı olacaktır. 10 adet eksik alanı olan bir servis için hepsi için tek tek servise gelip eksik olduğunu görmekten ise tek seferde tüm eksikler görülmüş olur.
İyi Çalışmalar Dilerim…
merhaba, evet haklısınız. Yazıdaki haliyle herbir error dönüşü düzeltmesinde bir sonrakini görebilecek. Error textler arka arkaya toplanıp tek seferde return edilirse userın işi kolaylaşabilir. Teşekkürler
Elinize sağlık , faydalı bir paylaşım.
Çok güzel bir yazı olmuş 🙂 yanlışlarımızı doğrularımızı görmüş olduk. Eline sağlık.
Emeğinize sağlık yazı çok açıklayıcı. Çoğu şeye detaylıca değinilmeye çalışılmış
Emeğinize sağlık çok faydalı bir paylaşım olmuş.
Elinize sağlık, çok güzel bir yazı olmuş. Bazı yerlerde “evet ya, aslında çok mantıklıymış, neden daha önce böyle yapmadım ki” dedim, teşekkürler!
if(KafaminIciDaginik)
{
DialogResult dr = MessageBox.Show(“Bu Makale Cük diye Oturdu Mu?”, MessageBoxButtons.YesNo);
switch(dr)
{
case DialogResult.Yes:
MessageBox.Show(“Hadi Şimdi Teşekküret ve Git yat.”);
break;
case DialogResult.No:
MEssageBox.Show(“Yalan atma, Bu Makale Cük diye oturdu. Kafan Rahatladı be.. Teşekkür et bari”);
break;
}
}
MessageBox.Show(“Teşekkürler Amca.. Eline Koluna, Beynine , Gözlerine, Kalbine Sağlık. Omuzlarımdan Yük düştüğünü hissettim”);
Güzel bi yazı olmuş.