Kurallar
Verse Kodu Stil Kılavuzu, tutarlı ve sürdürülebilir kodlar yazmaya yönelik kurallar sunar. Bu kurallara uyarak geliştiriciler okunaklılığı artırabilir, hataları azaltabilir ve işbirliğini kolaylaştırabilir. Standart hale getirilmiş bir kod stili hem şimdi hem de gelecekte proje üzerinde çalışan geliştiricilerin kodu anlamasını ve devam ettirmesini kolaylaştırmak için gereklidir.
Bu kılavuz öneriler sunar ancak son karar takımına aittir.
1. Yaygın Adlandırma Şekilleri
Adlandırma, okunabilir ve devam ettirilebilir bir kod için kritik öneme sahiptir. Kodunun her yerinde aynı adlandırma stilini devam ettirmeye çalışmalısın.
1.1 Yapılması Gerekenler
-
IsX
- genellikle bir soru soran mantık değişkenleri için kullanılır (örn. IsEmpty). -
OnX
- çerçeve tarafından çağrılan aşırı yüklenilebilir bir işlev. -
SubscribeX
- çoğunlukla bir OnX işlevi geçirerek X adlı çerçeve olaya abone ol. -
MakeC
- c oluşturucusunu aşırı yüklemeden c sınıfının bir örneğini oluştur. -
CreateC
- mantıksal yaşam süresini başlatarak bir c sınıfı örneği oluştur. -
DestroyC
- mantıksal yaşam süresini sonlandır. -
C:c
- c sınıfının tek bir örneğiyle çalışıyorsan C adını vermek yeterlidir.
1.2 Yapılmaması Gerekenler
-
Tür adlarını süslemek.
thing_type
veyathing_class
yerine sadecething
yeterlidir. -
Numaralandırma değerlerini süslemek.
color := enum{COLOR_Red, COLOR_Green}
yerinecolor := enum{Red, Green}
kullan.
2. Adlar
2.1 Türler küçük_harfli_alt_çizgili_yazı_tipi kullanır
Tür adları her zaman lower_snake_case
olmalıdır. Bu kural tüm türleri içerir: yapılar, sınıflar, tür tanımları, özellikler/arayüzler, numaralandırmalar vb.
my_new_type := class
2.2 Arayüzler sıfat olmalıdır
Arayüzler mümkün olan durumlarda yazdırılabilir, numaralandırılabilir gibi sıfatlar olmalıdır. Sıfatların doğru görünmediği durumlarda adın sonuna _interface ekleyebilirsin.
my_new_thing_interface := interface
2.3 Diğer her şey İlkHarfiBüyükBirleşikSözcüklerdir
Diğer tüm adlar ilk harfi büyük birleşik sözcüklerden oluşmalıdır. Modüller, üye değişkenleri, parametreler, yöntemler vb.
MyNewVariable:my_new_type = …
2.4 Parametrik Türler
-
Parametrik türleri t veya thing olarak adlandır. Burada thing, türün neyi temsil etmesi gerektiğini açıklar. Örneğin:
Send(Payload:payload where payload:type)
Burada parametre haline getirilmiş veriler olan, herhangi birpayload
türündePayload
gönderiyorsun. -
Birden fazla parametrik tür varsa
t
,u
,g
gibi tek harfler kullanmaktan kaçınmalısın -
Hiçbir zaman
_t
sonekini kullanma.
3. Biçimlendirme
Kod temelinin genelinde biçimlendirmenin tutarlı olmasını sağlamak önemlidir. Tutarlı bir kodun okunması ve anlaşılması hem senin için hem de diğer geliştiriciler için daha kolaydır. Proje için işe yarayan bir biçimlendirme stili seç.
Tutarlılığı sağlamanın bir örneği olarak aşağıdaki boşluk biçimlerinden birini seçebilir ve kod temelinin tamamında o biçimi kullanabilirsin:
MyVariable : int = 5
MyVariable:int = 5
3.1 Girinti
-
Girinti için dört boşluk kullan ve asla tab tuşunu kullanma.
-
Kod bloklarında süslü parantezler (parantezli) yerine girintili bloklar (boşluklu) kullanılmalıdır:
my_class := class: Foo:void = Print("Hello World")
option{a}
,my_class{A := b}
vb. tek satırlı ifadeler yazılan durumlar dışında.
3.2 Boşluklar
- Kodu bağlam için kısa tutmak anlamlı olmadıkça işleçlerin etrafında boşluk kullanmayı tercih et. İşlemlerin sırasını açıkça tanımlamak için süslü parantezler ekle.
MyNumber := 4 + (2 * (a + b))
-
Parantezlerin başına ve sonuna boşluk ekleme. Parantez içinde birden fazla ifade varsa tek boşlukla birbirinden ayrılmalıdır.
enum{Red, Blue, Green} MyObject:my_class = my_class{X := 1, Y := 2} Vector := vector3{X := 1000.0, Y := -1000.0, Z := 0.0} Foo(Num:int, Str:[]char)
- Tanımlayıcı ve türü bir arada tut, atama
=
işlecinin etrafına bir boşluk ekle. Tür tanımlarının ve sabit başlatma işleçlerinin (:=
) etrafına bir boşluk ekle.MyVariable:int = 5 MyVariable := 5 my_type := class
- Parantezler, tanımlayıcılar ve işlev imzalarının tür boşlukları için aynı önerileri takip et.
Foo(X:t where t:subtype(class3)):tuple(t, int) = (X, X.Property) Foo(G(:t):void where t:type):void Const(X:t, :u where t:type, u:type):t = X
3.3 Satır Sonları
-
Satır sonu ekleyeceksen boşluklu, çok satırlı bir biçim kullan.
Bunu Yap MyTransform := transform: Translation := vector3: X := 100.0 Y := 200.0 Z := 300.0 Rotation := rotation: Pitch := 0.0 Yaw := 0.0 Roll := 0.0
Daha okunaklı ve düzenlenmesi kolay. Bunu Yapma MyTransform := transform{Translation := vector3{X := 100.0, Y := 200.0, Z := 300.0}, Rotation := rotation{...}}
Tek satırda okunması zor.
- Numaralandırma başına yorum gerektiriyorsa veya bir satır sonu ekleyeceksen numaralandırmaları boşluklu, tek satırlı biçimde tanımla.
enum: Red, # Desc1 Blue, # Desc2
3.4 Ayraçlar
Devralmayan sınıf tanımları için parantez kullanma.
Bunu Yap |
|
Bunu Yapma |
|
3.5 Nokta-Boşluk Gösterimi Kullanma
Süslü parantez yerine nokta-boşluk ". " gösterimini kullanmaktan kaçın. Boşlukları ve olası bir karışıklık kaynağını ayrıştırmak görsel açıdan daha zordur.
Bunu Yapma |
|
Bunu Yapma |
|
4. İşlevler
4.1 Varsayılan olarak örtük dönüş
İşlevler son ifade değerlerini döndürür. Bunu bir örtük dönüş olarak kullan
Sqr(X:int):int =
X * X # Örtük dönüş
Herhangi bir açık dönüş kullanılıyorsa işlevdeki tüm dönüşler açık olmalıdır.
4.2 GetX işlevleri <decides><transacts>
olmalıdır
Benzer semantiklere sahip olup geçerli değerler döndürmeyebilecek alıcılar veya işlevler <decides><transacts>
olarak işaretlenmeli ve seçenek olmayan bir tür döndürmelidir. Çağıran işlev olası başarısızlığı işlemelidir.
GetX()<decides><transacts>:x
Bunun bir istisnası, koşulsuz olarak bir var
yazması gereken işlevlerdir. Başarısızlık değişikliği geri alır, bu nedenle dönüş türü olarak logic
veya option
kullanmayı gerekirir.
4.3 Tek Parametreli Yöntemler Yerine Genişletme Yöntemlerini Tercih Et
Tek türde parametresi olan bir modül yöntemi yerine genişletme yöntemlerini tercih et.
Bunu yapmak Intellisense'e yardımcı olur. Intellisense, Normalize(MyVector)
yerine MyVector.Normalize()
yazarak yazdığın yöntem adının her bir karakteriyle adlar önerebilir.
Bunu Yap |
|
Bunu Yapma |
|
5. Hata Kontrolleri
5.1 Tek satırlı Başarısız Olabilir İfade sayısını üç ile sınırla
-
Tek bir satırdaki koşullu kontrol/başarısız olabilir ifade sayısını en fazla üç ile sınırlı tut.
if (Damage > 10, Player := FindRandomPlayer[], Player.GetFortCharacter[].IsAlive[]): EliminatePlayer(Player)
-
Koşul sayısı üçten az olduğunda parantezli
()
if
biçimini tercih et.
Bunu Yap |
|
Kodu kısa ancak okunaklı tutar. |
Bunu Yapma |
|
Kodu okunaklılık geliştirmesi yapmadan gereksiz bir şekilde birden fazla satıra böler. |
-
Her ifade için ikiden fazla sözcük kullanılıyorsa tek bir satırda çoğu zaman en fazla iki ifade daha okunaklıdır.
if (Player := FindAlivePlayer[GetPlayspace().GetPlayers()], Team := FindEmptyTeam[GetPlayspace().GetTeamCollection().GetTeams()]): AddPlayerToTeam(Player, Team)
-
Kuralı şu şekilde de görebilirsin: Bir hata bağlamında tek bir satırda dokuzdan fazla sözcük kullanma. Limit aşıldığında boşluklu, çok satırlı biçimi kullan.
Bunu Yap |
|
Metin daha iyi okunur ve bağlam birden fazla satırda anlaşılabilir. |
Bunu Yapma |
|
Metnin ayrıştırılması zordur. |
- Birden fazla başarısız olabilir koşulu tek bir
<decides>
işlevinde gruplandırmak kodun okunuşunu ve yeniden kullanılmasını daha kolay hale getirir. Kod yalnızca bir yerde kullanılacaksa geçici bir işlevin olmadığı bir "bölüm" yorumu yeterli olabilir.
if:
Player := FindRandomPlayer[]
IsAlive[Player]
not IsInvulnerable[Player]
Character := Player.GetFortCharacter[]
Character.GetHealth < 10
then:
EliminatePlayer(Player)
Şu şekilde yeniden yazılabilir
GetRandomPlayerToEliminate()<decides><transacts>:player=
Player := FindRandomPlayer[]
IsAlive[Player]
not IsInvulnerable[Player]
Character := Player.GetFortCharacter[]
Character.GetHealth < 10
Player
if (Player := GetRandomPlayerToEliminate[]):
Eliminate(Player)
- Aynı kural for döngülerindeki ifadeler için geçerlidir. Örneğin:
set Lights = for (ActorIndex -> TaggedActor : TaggedActors, LightDevice := customizable_light_device[TaggedActor], ShouldLightBeOn := LightsState[ActorIndex]):
Logger.Print("Adding Light at index {ActorIndex} with State:{if (ShouldLightBeOn?) then "On" else "Off"}")
if (ShouldLightBeOn?) then LightDevice.TurnOn() else LightDevice.TurnOff()
LightDevice
Şu şekilde daha iyi okunur:
set Lights = for:
ActorIndex -> TaggedActor : TaggedActors
LightDevice := customizable_light_device[TaggedActor]
ShouldLightBeOn := LightsState[ActorIndex]
do:
if (ShouldLightBeOn?) then LightDevice.TurnOn() else LightDevice.TurnOff()
LightDevice
5.2 Bağımlı Hata İfadelerini Birlikte Gruplandır
Hata bağlamındaki bir koşul, başarılı olan daha önceki bir hata bağlamına bağımlı olduğunda mümkünse iki koşulu aynı hata bağlamında birlikte tut ve 5.1 numaralı kuralı izle.
Bunu yapmak kodun yerelliğini artırarak mantıksal anlayışı ve hata ayıklamayı kolaylaştırır.
Bunu Yap |
|
Bağımlı veya ilgili koşullar gruplandırılır. |
Bunu Yap |
|
Bağımlı veya ilgili koşullar gruplandırılır. |
Bunu Yapma |
|
Gereksiz girintiler akışı takip etmeyi zorlaştırabilir. |
Bunu Yapma |
|
Gereksiz girintiler akışı takip etmeyi zorlaştırabilir. |
Her bir potansiyel hatayı (veya hata grubunu) ayrıca işliyorsan hata bağlamlarını bölebilirsin.
if (Player := FindPlayer[]):
if (Player.IsVulnerable[]?):
EliminatePlayer(Player)
else:
Print("Player is invulnerable, can’t eliminate.")
else:
Print("Can’t find player. This is a setup error.")
6. Kapsülleme
5.1 Sınıflar Yerine Arayüzleri Tercih Et
Mantıklı olduğu durumlarda sınıflar yerine arayüzleri tercih et. Bunu yapmak uygulama bağımlılıklarını azaltır ve kullanıcıların çerçeve tarafından kullanılabilen uygulamalar sağlamasına izin verir.
5.2 Gizli Erişimi Tercih Et ve Kapsamı Kısıtla
Sınıf üyeleri çoğu durumda 'gizli' olmalıdır.
Sınıf ve modül yöntemleri, uygun olduğunda ‘iç' veya 'gizli’ olacak şekilde, mümkün olduğunca kısıtlayıcı bir kapsama alınmalıdır.
6. Olaylar
6.1 Olayların Sonuna Event, İşleyicilerin Başına On Eki Getir
Abone olunabilir olaylar veya temsilci listesi adlarının sonuna 'Event', olay işleyici adlarının başına ise 'On' getirilmelidir.
MyDevice.JumpEvent.Subscribe(OnJump)
7. Eşzamanlılık
7.1 '' İşlevlerini 'Async' ile Süsleme
'
Bunu Yap |
|
Bunu Yapma |
|
Dahili olarak bir şeyin gerçekleşmesini bekleyen bir '
AwaitGameEnd()<suspends>:void=
# Oyun sonunu beklemeden önce diğer şeyleri ayarla…
GameEndEvent.Await()
OnBegin()<suspends>:void =
race:
RunGameLoop()
AwaitGameEnd()
8. Öznitelikler
8.1 Öznitelikleri Ayır
Öznitelikleri ayrı bir satıra yerleştir. Özellikle öznitelikler aynı tanımlayıcıya eklenirse daha okunaklı olur.
Bunu Yap |
|
Bunu Yapma |
|
9. Using İfadeleri
9.1 Using İfadelerini Alfabetik Sıraya Koy
Örneğin:
using { /EpicGames.com/Temporary/Diagnostics }
using { /EpicGames.com/Temporary/SpatialMath }
using { /EpicGames.com/Temporary/UI }
using { /Fortnite.com/UI }
using { /Verse.org/Simulation }