Sabitleri nereye koymalı ve neden?


34

Çoğunlukla büyük uygulamalarımızda, genellikle "sabitler" için yalnızca birkaç yerimiz vardır:

  • GUI ve iç kalıcılar için bir sınıf (Sekme Sayfa başlıkları, Grup Kutusu başlıkları, hesaplama faktörleri, numaralandırmalar)
  • Veritabanı tabloları ve sütunları için bir sınıf (bu bölüm kod oluşturulur) artı bunlar için okunabilir adlar (el ile atanır)
  • Uygulama mesajları için bir sınıf (günlüğe kaydetme, mesaj kutuları vb.)

Sabitler genellikle bu sınıflarda farklı yapılara ayrılır. C ++ uygulamalarımızda, sabitler yalnızca .h dosyasında tanımlanır ve değerler .cpp dosyasına atanır.

Avantajlarından biri, tüm dizgilerin vb. Tek bir merkezi yerde olması ve herkes bir şeyin değiştirilmesi gerektiğinde onları nerede bulacağını bilmesidir.

Bu, özellikle proje yöneticilerinin insanlar gelir ve gider gibi göründüğü bir şeydir ve bu şekilde herkes bu önemsiz şeyleri uygulamanın yapısına girmeden değiştirebilir.

Ayrıca, benzer Grup Kutuları / Sekme Sayfaları vb. Unvanını bir kerede kolayca değiştirebilirsiniz. Diğer bir husus, sadece bu sınıfı yazdırabilir ve başlıkları sezgisel olup olmadığını ve kullanıcıya gönderilen iletilerin çok ayrıntılı veya kafa karıştırıcı vb. Olup olmadığını kontrol edebilecek bir programcıya veremezsiniz.

Ancak bazı dezavantajları görüyorum:

  • Her bir sınıf, sabit sınıflara sıkıca bağlıdır
  • Bir sabit ekleme / çıkarma / yeniden adlandırma / taşıma, uygulamanın en az% 90'ının yeniden derlenmesini gerektirir (Not: Değerin değiştirilmesi, en azından C ++ için değildir). 1500 sınıflı C ++ projelerimizden birinde bu, yaklaşık 7 dakika derleme süresi (önceden derlenmiş başlıkları kullanarak; onlarsız yaklaşık 50 dakika) artı belirli statik kütüphanelere karşı yaklaşık 10 dakika bağlantı anlamına gelir.
  • Visual Studio Compiler ile hıza göre optimize edilmiş bir sürüm oluşturmak 3 saate kadar sürebilir. Sınıf ilişkilerinin büyük miktarda kaynak olup olmadığını bilmiyorum ama olabilir.
  • Geçici olarak kodlama yapan dizgilere doğrudan koda girersiniz, çünkü bir şeyi çok hızlı bir şekilde test etmek ve sadece bu test için (ve muhtemelen her biri için) 15 dakika beklemek istemezsiniz. "Bunu daha sonra düzelteceğim" deyince herkes bilir.
  • Bir sınıfın başka bir projede tekrar kullanılması her zaman bu kadar kolay değildir (özellikle diğer sıkı bağlantılardan dolayı, ancak sabit kullanım kolay değildir.)

Böyle sabitleri nerede saklardın? Ayrıca, proje yöneticinizi yukarıda sıralanan avantajlara da uyan daha iyi kavramlar olduğuna ikna etmek için hangi argümanları getirdiniz?

C ++ 'a özgü veya bağımsız bir cevap vermekten çekinmeyin.

Not: Bu sorunun öznel olduğunu biliyorum ama dürüst olmak gerekirse, bu tür bir soru için bu siteden daha iyi bir yer bilmiyorum.

Bu projede güncelleme

Derleme zamanı
olayıyla ilgili haberlerim var: Caleb ve gbjbaanb'ın gönderilerinin ardından, zamanım olduğunda sabit dosyamı diğer birkaç dosyaya böldüm. Sonunda projemi, artık çok daha kolay olan birkaç kütüphaneye böldüm. Serbest bırakma modunda derlemek, veritabanı tanımlarını içeren otomatik olarak oluşturulan dosyanın (tablo, sütun adları ve daha fazlası - 8000'den fazla simge) ve serbest bırakma modunda devasa derleme sürelerine neden olan belirli karmaları oluşturduğunu gösterdi.

MSVC'nin DB sabitlerini içeren kütüphane için optimize edicisini devre dışı bırakmak artık Projenizin toplam derleme süresini (birkaç uygulama) sürüm modunda 8 saate bir saate düşürmemizi sağladı!

MSVC'nin neden bu dosyaları optimize etmek için bu kadar zor zamana sahip olduğunu henüz bulamadık, ancak şimdilik bu değişiklik artık yalnızca gecelik yapılara dayanmak zorunda olmadığımız için büyük bir baskı oluşturuyor.

Bu gerçek - ve daha az sıkı eşleşme, daha iyi tekrar kullanılabilirlik vb. Gibi diğer faydalar - "sabitleri" bölmek için harcanan zamanın sonuçta kötü bir fikir olmadığını gösterdi ;-)

Update2

Bu soruya hala dikkat çekildiğinden:
Son birkaç yıldır yaptığım şey:

Her değişkeni, değişkeni, vb. Bununla tamamen ilgili olan kapsamı içine koyun: Bir sabiti yalnızca tek bir yöntemde kullanırsanız, onu bu yöntemde tanımlamanız uygundur. Tek bir sınıf ilgileniyorsa, o sınıfı özel bir uygulama detayı olarak bırakın. Aynısı isim alanı, modül, proje ve şirket kapsamı için de geçerlidir. Aynı işlevi yardımcı fonksiyonlar ve benzerleri için de kullanıyorum. (Genel bir çerçeve geliştirirseniz, bu% 100 uygulanmaz.)

Bunu yaparak yeniden kullanılabilirliği, test edilebilirliği ve bakımını yalnızca derlemeye daha az zaman harcayamayacağınız bir dereceye kadar (en azından C ++) değil, aynı zamanda hata ayıklama konusunda daha az zaman vererek, aslında yeni özellikler geliştirmek için daha fazla zaman harcarsınız. Aynı zamanda, bu özellikleri geliştirmek daha hızlı çalışacaktır çünkü daha fazla kodu daha kolay kullanabilirsiniz. Bu, merkezi sabitlerin büyük bir olasılıkla sahip olabileceği herhangi bir avantajdan daha ağır basar.

Daha fazla bilgi için özellikle Arayüz Ayrıştırma İlkesine ve Tek Sorumluluk İlkesine bir göz atın .

Kabul ederseniz, Caleb'in cevabını oylayın, çünkü bu güncelleme temel olarak söylediklerinin daha genel bir parçası.


2
şahsen ben UI başlık veya mesaj dizeleri hiç sabit olarak olmazdı. Onları app.config
jk

1
Şu an nasıl yaptığınızı beğeniyorum - dezavantajlarınızı anlıyorum ama bununla başa çıkmak zorunda kalabiliriz.
bigtang

1
Büyük bir Java projesinde de aynı problemi gördüm ... Büyük bir "sabit" arayüz, içindeki herhangi bir şeyi değiştirip tutulması yeniden derlemek için 15 dakika bekleyin. Caleb ile birlikteyim: Doğal olarak ait oldukları sabitleri, onları kullanan koda yakın bir şekilde gruplandırın. Onları ayrı tutmaları, çünkü sabit oldukları için işe yaramaz bir OKB egzersizidir.
Michael Borgwardt

Sıkı kavrama bir sorun değildir, çünkü gerçekten istediğiniz şey budur. Sen istemek için sabitler dosyasında bir değişiklik kaynak dosyalarının muhtemelen çok etkiler. (Tabii ki başka problemleriniz de var).
gnasher729

@ gnasher729, yalnızca birçok sınıf aynı sabiti kullanıyorsa geçerlidir. Sınıfların asla ilişkili olmadıkları sabitlere sıkı sıkıya bağlı olmasını istemezsiniz. Başka bir projede kopyalamadan veya izole edilmiş testler yapmadan tekrar kullanmayı deneyene kadar ilk başta bir sorun görünmeyebilir
Tim Meyer

Yanıtlar:


29

Bir sınıfa özgü sabitler o sınıfın arayüzüne girmelidir.

Gerçekten yapılandırma seçenekleri olan sabitler bir yapılandırma sınıfının parçası olmalıdır. Bu sınıftaki yapılandırma seçeneklerine erişim sağlayıcılar sağlarsanız (ve bunları başka yerlerdeki sabitlerin yerine kullanırlarsa), birkaç seçeneği değiştirdiğinizde tüm dünyayı yeniden derlemeniz gerekmez.

Sınıflar arasında paylaşılan ancak yapılandırılması amaçlanmayan sabitler makul bir şekilde kapsamalıdır - onları özel kullanımlara sahip dosyalara ayırmaya çalışın, böylece bireysel sınıflar sadece gerçekten ihtiyaç duydukları şeyi içerir. Bu, bu sabitlerin bazılarını değiştirdiğinizde derleme sürelerinin azaltılmasına yardımcı olacaktır.


1
İlgilendiğiniz takdirde: Cevabımı ve diğerlerini takip ederek, elde ettiklerimle ilgili sorumu güncelledim
Tim Meyer,

6

Büyük sabitler sınıfınızı, örneğin forma göre bir çok küçük dosyaya bölmek istediğinizi söyleyebilirim. Bu, sabit dosyaya bu kadar büyük bir bağımlılığınızın olmamasını sağlar, bu nedenle bir dize eklemek veya güncellemek daha sonra toplam bir yeniden derleme gerektirmez. Bu dosyaları hala merkezi bir konumda saklayabilirsiniz, ancak (örn.) Her bir iletişim kutusu için, uygun şekilde adlandırılmış sabitleri olan 1 dosya vardır. Ardından, bu dosyaları yalnızca yeniden derlemeyi büyük ölçüde azaltan ilgili iletişim dosyalarına ekleyebilirsiniz.

Ayrıca dizeleri işlemek için GNU GetText yardımcı programları gibi bir şey kullanmanızı öneririm, çeviri için tasarlanmıştır, ancak metni başka bir şeye değiştirmek için de işe yarar. Onları bir dizge kaynağına koyabilirsiniz, ancak ID ile girildiklerinde çalışmanın daha zor olduğunu düşünüyorum, GetText yardımcı programları orijinal bir dizge tarafından kilitlenir - gelişmeleri çok kolaydır.


Buna bir şans verebilirim. Başlıkları vb. Olan sabitler sınıfı çeşitli yapılara bölündüğü için, başlangıç ​​olarak yapı başına bir sınıf yapabilirim. GNU meselesinden emin değiliz, genellikle çalışma zamanında, sadece geliştirme sırasında dizgilerimizi değiştirmek istemiyoruz. Ancak, gelecekte başka bir dile tercüme etmek zorunda kalmamız durumunda Qt'un çeviri mekanizmasını kullanıyoruz.
Tim Meyer

İlgilendiğiniz takdirde: Cevabımı ve diğerlerini takip ederek, elde ettiklerimle ilgili sorumu güncelledim
Tim Meyer

2

Not: Ben bir C ++ geliştiricisi değilim ... ama benim düşüncem: Konfigürasyon dosyalarını kullanma arasındaki fark hakkında @ jk'nin yorumunu izlemeniz gerekir. DotNet'te bu tür bilgileri depolamak için kullanılan kaynaklar dosyası vardır. Windows Formlarında, her form için VS'den bir kaynak dosyası korunur.

Paylaşılması gereken bir genel sabit olmadığı sürece, kullanım alanı dışında bir sabitin değerini göremiyorum. Bahsettiğiniz gibi, en azından gelişim sırasında bunu sürdürmek zor olacaktır. Ayrıca, ad çakışmaları olabilir. Başka bir şey, verilen bir sabiti kimlerin kullandığını bilmek zor olabilir.

Şimdi, programcı olmayanların bilgileri gözden geçirmesini istiyorsanız, GUI için, onlar için ekranı yakalarsınız. Veri tablosu girişlerini gözden geçirmelerini istiyorsanız, verileri Excel'e veya benzeri bir öğeye verebilirsiniz.

Hala merkezi bir konum yaklaşımı ile gitmek istiyorsanız ve tüm sabitlerinizi büyük bir dosyaya yerleştirmek istiyorsanız, her geliştirici her aralığın sonunda merkezi bir dosyaya güncellenen paylaşılan bir dosya kullanabilir. Veriler, geliştirme aşamasında kullanılan bireysel dosyalardan gelecektir. Bu kolayca otomatikleştirilebilir veya manuel olarak yapılabilir. Ancak, dediğim gibi muhtemelen almanız gerekmeyen bir risk.


2

Genel bir çözüm yok. Kendinizi bir sabitin performansı, kullanılabilirliği, güvenliği ve yaşam döngüsü hakkında sorun.

Kapsamları ne kadar yakınsa, performansı o kadar yüksek olur.

Mantıksal olarak ve kapsamlarının dışında gruplandıkça yeniden kullanılabilirlik de artar.

Kostantlar ne kadar az erişilebilir olursa güvenlik de o kadar yüksek olur.

Bir sabitin ömrü ne kadar yüksek olursa, kullanılabilirlik için nereye koyduğunuza o kadar az dikkat eder.

Bir sürüm numarası gibi bir sabit, bir tür tezahürde tanımlanacaktır. Sınıf içinde bir hata fonksiyonunun hata kodu tanımlanacaktır. Hata kodu, yüksek kullanım ömrüne sahip bir şey olabilir (= neredeyse hiç değişmez). Sabit bir dosyaya koymak sadece gereksiz şeylerle dosyayı spam.

Sabit, sabit bir karaktere sahip olduğunda, bir değişken (sürüm numarası gibi), dışardan daha fazla koyabilirsiniz. Sabit ne kadar az değişken olursa, o kadar sabit, kapsamı içinde o kadar fazla yer alması gerekir. Hata ayıklama sırasında derleme süresini azaltmak için dışarıda bırakmak mantıklıdır.

Ancak, ilk probleminiz derleme zamanıdır. Yani soru, doğru soruyu sorup sormaman. Uygulamanızın derleme süresi çok yüksekse, parçaların birbirinden bağımsız çalışması için daha modüler hale getirmenin bir yolunu düşünmelisiniz. Kısmen derleyin ve eşyalarınızı bağımsız olarak test edin. Ünite testleriniz uygun şekilde yapılmışsa ve doluysa (ki aslında çok fazla iş var), endişelenmenize gerek kalmadan işleri kolayca değiştirebilirsiniz. Ve sonra soru tamamen farklı bir sürüş alır.


1

Tüm bu sabitleri bir tür yapılandırma dosyasına koymanızı öneririm. Java uygulamaları için genellikle .properties dosyalarını kullanıyoruz, her satırda "(key) = (value)" olarak biçimlendirilmiş basit bir metin. Örnek

MainPanel.Title = Uygulamamıza Hoşgeldiniz
DB.table.users = TBL_USERS
logging.filename = application.log

Daha sonra bu dosyayı çalışma zamanında yükleyin, bir anahtara bakmanıza ve bir değer geri almanıza izin veren bir önbellek doldurun. Bir sabite ihtiyacınız olduğunda önbelleği sorgulamanız gerekir. Anahtarlarınızı bir yerde bulundurmaya ihtiyacınız olacak ve önbellek genel olarak erişilebilir olmalıdır, ancak sabitlerin gerçek değerlerini değiştirdiğinizde, yeniden derlemeye gerek yoktur, sadece uygulamayı yeniden başlatmak mümkün olabilir (veya Gerçekten çok süslü olmak, çoklu .properties dosya ve önbelleklere sahip olmak ve uygulamaya çalışma zamanında bir önbellek yeniden yükleme imkanı vermek).

Bir uygulama için, bu SO sorusunu buldum: https://stackoverflow.com/questions/874052/properties-file-library-for-c-or-c (Google'da yapılan aramadaki ilk isabetti - yapmadım) Aslında bu yazılımı kendim kullandım).


C ++ projeleri için, sadece bir değeri değiştirdiğimizde sabitleri yeniden derlememiz gerekir. Bunun nedeni, değerlerin bir .cpp dosyasına atanmasıdır. Ancak bir sabit eklemek / kaldırmak / yeniden adlandırmak / taşımak için hala tam bir yeniden kurulum gerekir
Tim Meyer

@TimMeyer: Sabitleri birden fazla dosyaya bölerseniz, sabit eklemek / çıkarmak sadece o dosyaya bağlı olan dosyaları etkiler, doğru mu?
SinirliFormsDesigner ile

Doğru. Asıl sorun, eğer önerirsem, insanların "avantaj" olarak listelediklerimden birini kaybedeceklerini söyleme eğiliminde olmalarıdır
Tim Meyer

Ancak, aynı yerde birkaç sabit dosya koymak hakkında hiç düşünmedim
Tim Meyer

+1. @Tim Meyer: Bu amaçla, derleme zamanı kontrolünün, tasarruf ettiğinden çok daha fazla maliyeti var. Ayrıca, uluslararasılaştırılmaya ihtiyacınız olursa ne yapacaksınız?
kevin cline
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.