“Yapılmadıysa bir şeyler yap” terimi için terim (ya da “kalıp”?) [Kapalı]


54

Kulağa oldukça basit geliyor, biliyorum, ama son zamanlarda bir meslektaşım bana bir yöntemin startHttpServeranlaşılmayacak kadar karmaşık olduğunu söylemişti, çünkü sadece zaten çalışmıyorsa, sunucuyu başlatıyor. "Cidden mi? Bunu yıllardır yapıyorum - programlamada çok yaygın bir kalıptır." Kabul etmeyi umduğumdan çok daha fazla, tüm programlama topluluğunun kendi bakış açısının gerisinde olduğunu ve nezaketle hissettiğimi gösteren bazı kanıtlanmış kanıtlarla geri döndüğünü kabul ediyorum.

Soru : Eğer gerekli eylem yürürlükte ise, çalışmayan bir yöntem kavramının arkasında belgelenmiş bir tasarım deseni var mı? Veya bir kalıp değilse, adı da var mı? Olmazsa, bu şekilde bir yöntem yazmayı düşünmenin çok karmaşık olduğunu düşünmek için herhangi bir neden var mı?


6
önbellekleme gibi sesler - ve genellikle gerçekten karmaşık olarak kabul edilir (ayrıca bkz. $ {bir şey} 'i {$} birine nasıl açıklayabilirim? )
gnat

8
3 farklı cevabınız var, ama en iyi cevap, hepsini uygulayın: orijinal işlevi yeniden adlandırın, kodunu iki işleve ayırın (ikisinden birinin adını şimdi alır startHttpServer) ve evet, "idempotent" terimi burada geçerlidir iyi.
Doktor Brown

8
Meslektaşınız ne tür bir karşı kanıt sağlıyor? Bir link verebilir misiniz?
Robert Harvey,

5
Meslektaşınızın tekliflerini nereden kaynak gösterdiğini merak ediyorum. En azından Yığın Taşması ve Yazılım Mühendisliği çevresinde, bu işlev en kötü şekilde adlandırılmış, ancak olağandışı davranışlarda bulunmayacaktı. Unutmayın, çünkü bir blogda bir yerlere birisinin programlama topluluğunun tüm görünümünü temsil ettiği bir şey koyduğu için aklınızda bulundurun. Martin Fowler gibi büyük isimler bile zaman zaman çok garip şeyler söylüyor. Hepimiz sadece insanlarız.
T. Sar - Monica,

4
"Daha önce yapılmadıysa bir şeyler yap" deyince "sistemi bu duruma getirin" olur. Elbette, sistem zaten bu durumda ise, yöntem hiçbir şey yapmaz - bu beklenen davranış olacaktır.
T. Sar - Monica

Yanıtlar:


127

NickWilliams'ın zaten söylediği gibi : OP'nin tanımladığı kavram idempotent (isim Idempotency ) olarak adlandırılıyor . Gerçekten de, özellikle üst düzey API'lerde yaygın bir uygulamadır.

AMA: İşlevi yeniden adlandırın.

startHttpServerAramak yerine makeSureHttpServerIsRunningveya ensureHttpServerIsRunning.

Bir işlev çağrıldığında startHttpServer, okuyucular bir HTTP sunucusu başlatmasını bekler; arka arkaya on kez çağrıldığında, çalışan on sunucuya sahip olacağım. İşleviniz çoğu zaman bunu yapmaz. Ek olarak, "start" olan ad, yalnızca bir sunucunun çalışmasını istiyorsanız, işlevin zaten çağrılıp çağrılmadığını izlemem gerektiğini belirtir.

Bir işlev çağrıldığında makeSureHttpServerIsRunning, bir HTTP sunucusunun çalıştığından emin olmak için gerekli olan şeyleri yapacağını ve büyük olasılıkla çalışıp çalışmadığını kontrol ederek ve başka şekilde başlatacağını düşünüyorum. Ayrıca, işlevin sunucunun gerçekten çalıştığından emin olduğunu varsayıyorum (bir sunucuyu başlatmak, henüz tam olarak çalışmadığı bir zamanı içerebilir).


83
Bu. Şahsen onun yerine "Ensure" kullanıyorum. Mesele şu ki bunun takımınızda anlaşılan bir adlandırma şeması haline gelmesi gerektiğidir.
Öforik,

3
veya daha önceden başlatılmışsa, bir istisna atmaya başlayın. sqlconnection.open gibi
Ewan

9
Ben her zaman "zaten" ismini "yapmamışsanız" işlevini kullanıyorum.
Kaz

3
Sık gördüğüm başka bir isim getOrCreateSomething, sadece ilk aramada yaratan ve sonra sadece bir şeyler döndüren bir şey
Fabich

5
@aroth Kullanılabilir bir liman bulup geri getirmeyi denemeyi beklemeyeceğinizden emin misiniz? Ya da sadece kötü yazılmış mı? ;)
jpmc26 5

33

Yeniden adlandırın EnsureServerRunning.

Tamamen belirsizdir ve çalışıyorsa (eğer değilse) yeniden başlatmayı gerektirmeden çalıştığından emindir.

(Alternatif:? StartServerIfNotRunning)


1
Arayanların çoğu, sunucunun çağrıdan sonra çalışmasına özen gösterir. Bu nasıl başarılır, umrunda değil.
gnasher729

29

Gerçekten bir tasarım kalıbı değil, yönteminizi belirsiz olarak adlandırırım . Bu terim genellikle uzak çağrılara atıfta bulunmak için kullanılır, ancak açıklama yaptığınız eşleşmeye benziyor.

Idempotent Yöntemleri. Metotlar aynı zamanda "boşuna gitme" özelliğine de sahip olabilirler (hata veya sona erme sorunlarının yanı sıra), N> 0 özdeş isteklerinin yan etkileri, tek bir istekle aynıdır. ( W3.org'dan )

Buradaki sunucu yan etkisi, yöntem çağrıldığında http sunucusunun başlatılmış olmasıdır. Bunu yapan bir yöntemle yanlış bir şey görmüyorum.

Bir tasarım modeline ihtiyacınız varsa, sanırım httpServer sunucunuzu başlatıldığında başlatılan bir singleton olarak gösterebilirsiniz.


5
Fonksiyon olduğunu değil İdempotent kez arayarak http sunucusu başlar ve bunu çağırarak ikinci kez yapmazsa. Kelimenin tam anlamıyla idrarsızlığın tam tersi. Her çağrı yeni bir http sunucusu başlattıysa idempotent olur .
Polygnome,

36
@ Polygnome Wikipedia, bağımsızlığı, genel olarak Nick'in tanımına uyan f (f (x)) = f (x) olarak tanımlar. Burada işlev girişi ve çıktısı örtük sunucu durumu olacaktır, bu nedenle “sunucu çalışıyor” durumu bu işlev için sabit bir nokta olacaktır. Belki burada Wikipedia makalesini yanlış anlıyorum, diğer referanslara link verebilir misiniz?
amon

16
@Polygnome: bu cevap doğrudur, idrarsızlık, bir defadan fazla mı yoksa birden fazla mı çağrıldıklarının önemli olmadığı fonksiyonları ifade eder, sonuç daima aynı kalır. Burada sonuç, çalışan bir http servisidir, fonksiyonun çağırılma sayısından bağımsız olarak.
Doktor Brown,

14
Karışıklık, özünde boşa gitmenin işlevlere uygulanan matematiksel bir kavram olduğu gerçeğinden geliyor. Tanım, bunlar için hoş ve basit ve aynı zamanda saf işlevsel diller için de iyi çalışıyor. Yan etkileri getirdiğiniz anda karmaşıklaşır - işlevi yürüttüğünüz ortamı işlevin (örtük) bir argümanı ve çıktısı olarak düşünmelisiniz. Eğer bu durum fonksiyona yapılan çağrılar tarafından değiştirilmezse, önemsizdir, aksi takdirde olmaz. Bu durumda, ilgili durum "http sunucusu çalışıyor" şeklindedir - bu nedenle işlev bağımsızdır.
Voo

10
@ Polygnome Üzgünüz, yanılıyorsunuz. Önemsiz olan, isteğin bir kez mi yoksa bir kereden fazla mı yürütüldüğü ile aynı etkiye sahip olduğu anlamına gelir. İsteğin N kopyası alındığında, N http sunucularının başlatılması kesinlikle kesin değildir.
Kaz

7

Bunu uygulamak biri olarak aracı , startHttpServer, bunun en basit pürüzsüz ve yapmaya çalışıyorum gerektiğini sorunsuz kullanmak ...

İşlevin mantığı

Teknik olarak, bölme tarafından startHttpServer'ın mantığı 2 fonksiyonlarına ve onları çağıran ayrı ayrı , bütün olup ne hareketli startHttpServer s' Idempotency sen ne olduğu (üçüncü bir işlevi hem mantık sarın sürece Dahası ... yerine iki işlevi çağıran koduna startHttpServerilk olarak), bu sizi aramak zorunda kaldığınız her yere katlanarak kopyalayarak, KURUTMALI kod yazmaya zorlar startHttpServer. Kısacası, kendisini işlev startHttpServer olarak adlandırmak zorundadır isHttpServerRunning.

Yani benim açımdan:

  • Uygulamak isHttpServerRunningbu zaten bağımsız gerekebilir çünkü işlevini ...
  • Uygulamak startHttpServerkullanmak yapım isHttpServerRunningbuna göre bir sonraki eylemi tanımlamak için ...

Yine de, startHttpServerbu fonksiyonun kullanıcısının ihtiyaç duyabileceği herhangi bir değeri geri getirebilirsiniz, örneğin:

  • 0 => sunucu başlatma hatası
  • 1 => sunucu başlangıç ​​başarısı
  • 2 => sunucu zaten başlatıldı

İşlevin adlandırma

Her şeyden önce, kullanıcının temel amacı nedir? HTTP sunucusunu başlatmak için değil mi?

Temel olarak, daha önce başlamış olan bir şeye başlamak isteyen bir problem yoktur, AKA 1*1=1. Bu yüzden, en azından benim için, " ensureHttpServerIsRunning" olarak adlandırmak, kritik bir şekilde ihtiyaç duyulmuyor gibi görünüyor, işlevin adının ne kadar uzun, doğal ve akılda kalıcı olacağını umursuyorum.

Şimdi, başlık altında fonksiyonun nasıl çalıştığını bilmek istiyorsanız, bunun için dökümantasyon veya kod kaynağı var.

Sen öğrenmek sen ise bir kez fonksiyonunu yazma bunu birden çok kez ...

Her neyse, startHttpServerkendisinden daha kısa, daha basit ve daha açık olan şeylere bağlı kaldım ensureHttpServerIsRunning.


1
Özellikle, yöntem kök dizini, güvenlik ayarları, muhtemelen bir port numarası gibi bazı yapılandırma değişkenleri almak zorunda olduğundan, burada "start" ile% 100 rahatım.
user949300,

@ user949300: "sureHttpServerIsRunning" ın arayanı, yapılandırma, kök dizin vb. ile ilgilenmez.
gnasher729

2
@ gnasher729 http sunucusunun bir Singleton olduğunu varsayar. Singletons kötüdür. Ve burada muhtemelen uygunsuz. Birinin kolayca birden fazla portta birden fazla sunucusu olabilir. Gerçekten yalnızca bir http sunucusu varsa, bu yöntemin tamamı IMO, kötü tasarım Program başlatma sırasında sunucuyu bir kez başlatmak daha iyidir.
user949300,

2

Sanırım meslektaşın bunun startHttpServerçok şey demek istediğini söyledi :

  • Sunucunun zaten çalışıp çalışmadığını kontrol etmek,
  • Gerekirse sunucuyu başlatmak.

Bunlar, ilgisiz kod bölümleridir. Örneğin, bir masaüstü uygulamasının başlatıldığında zaten çalışmamasını sağlaması gerektiğinde benzer bir durum söz konusudur; Uygulama örneklerini işleyen bir kod parçası (örneğin bir muteks kullanarak) ve uygulama mesajı döngüsünü başlatan kod olacaktır.

Bu , bir değil en az iki yönteme sahip olmanız gerektiği anlamına gelir :

  • isHttpServerRunning: boolean
  • startHttpServer

Uygulama giriş noktası önce yöntemi, sonra da dönüş değeri ise ikincisini çağırır false. Şimdi, her yöntem bir ve bir şey yapıyor ve anlaşılması kolaydır.


Already Sunucunun zaten çalışıp çalışmadığını bilmek için gereken mantık çok karmaşıksa, birden çok yönteme ayrılması gerekebilir.


21
Şimdi iki işlevi çağıran başka bir şey iki şey yapıyor, artı işlevleri ayrı ayrı göstermek yarış koşullarına neden olabilir. Beleş yemek yok.
whatsisname,

1
Bu meslektaş için çok fazlaysa, iyi şanslar.
gnasher729

@ gnasher729: bu cevap sizinkilerle çelişmiyor - tam tersi, yöntemin yeniden adlandırılmasını ikiye bölmekle birleştirmek gerçekten iyi bir fikir olabilir. Ve gerçek kodu görmediğimiz sürece, kodun ne kadar karmaşık olduğunu bilmiyoruz.
Doktor Brown

10
Bu cevap, soyutlama ve NEM'e karşı çıkıyor. Ya startHttpServerkodda birden fazla yer denirse? Birden çok benzer satır her yere kopyalanmalı mı? Bu, tüm fonksiyonlarla yapılmalı mı? Çok yakında programın sonsuz büyüklüğü olacak.
JacquesB

3
Bu yaklaşımın ilk yan etkisinin, startHttpServeryöntemin başlangıcının kabaca görüneceği şeklinde olduğunu düşünüyorum if (isHttpServerRunning()){ return; }. Bir işletme kuralını, "zaten çalışıyorsa http sunucusunu başlatmak için geçerli değil" olduğunu, ancak daha sonra bu kuralı uygulamak için başkalarının sorumluluğunu üstlendiğini iddia ediyorsunuz. Geçici olarak ve arayabilecekleri her yerde tekrar tekrar startHttpServer.
17'de

2

Dil belirtmediğiniz için, JavaScript’te birçok kütüphanede "once" işlevi vardır, örneğin Underscore . Yani, bu size tanıdık gelirse, "bir kez" bir kalıp olarak adlandırın ve muhtemelen yönteminizi yeniden adlandırın.

Kendim, Java'dan daha çok geliyor, "önbellekleme" veya "tembel değerlendirme" terimleri akla geliyor. "Idempotent" teknik olarak doğru ve iyi bir seçim, özellikle. daha işlevsel bir geçmişiniz varsa.


Sunucu durdurulabilirse, "bir kez" olmayabilir.
gnasher729

@ gnasher729. Nadiren kullanılan bir restartHttpServer()yöntem hayal edebiliyorum . Ama sadece durmak - orada kullanım durumu nedir? Sporadik bağlantı hatalarını sever misiniz? :-)
user949300,

Yalnızca HTTP sunucusunu durdurmak için bir kullanım durumu olması gerekmez, çünkü programın kendisinde harici bir şey tarafından durdurulmuş olabilir - HTTP sunucusu farklı nedenlerden dolayı ölmüş ve ölmüş olabilir; vs.
Dave Sherohman,

Dave, bir çarpışma "istisnai" ve bu şekilde ele alınması gerekiyor. Ayrıca, herhangi bir zamanda bir kaza olabileceğinden , kodunuzun her satırı olmak zorunda olmaz ensureRunning()mıydı? :-) Yönetici durdurma gelince, yönetici bir şeyi değiştirmeye veya düzeltmeye çalışırken bu diğer kodun sürekli olarak yeniden başlatılması inanılmaz derecede sinir bozucu ve yanlış olacaktır. Yönetici kodu değil, yeniden başlatsın.
user949300,

-2

Ben tercih ederim startHttpServerIfNotIsRunning.

Bu şekilde, durum yöntem yönteminde zaten açıkça belirtilmiştir. Ensureveya makeSureteknik bir ifade olmadığı için bana biraz belirsiz geliyor. Ne olacağını tam olarak bilmiyoruz gibi geliyor.


Anadili olmadığınızı düşünüyorum. Çünkü ne yaptığımızın tam olarak tanımlandığından emin olun . Ancak yine de, belgelerin ve API'lerin anadili İngilizce olanlardan anlaşılır olması gerekmemesi gereken bir nokta.
Voo

1
Teşekkürler tam olarak ne Ensureanlama geldiğini. Hala teknik bir ifade için bu kelimeyi sevmiyorum. Ensurebir insandır. Bir sistem hiçbir şeyi garanti edemez, sadece yapması gerekeni yapar.
Herr Derb,

2
@Voo - Ben yerli bir konuşmacıyım ve ne anlama geldiğinden emin değilim.
Jonathan,

Buraya gönderen herkes internete erişebildiğinden, bunun ne anlama geldiğinden emin olmasaydı neden 'Güvence' tanımına bakmıyorlar? Biraz önemsiz ... pek çok insan, bu kelimelerden birini kullanmanın diğerlerini istemeden “yasal” olarak sorumlu kılacağının farkında olmadan 'Güvence' ve 'Güvence' kullanımını değiştiriyor.
Dunk

@jcast: Cidden mi?
gnasher729

-3

Meslektaşınızın size söylemesi gereken şey, bu yöntemi yazan hiçbir işiniz olmadığıdır. Zaten birçok kez yazılmış ve yazmanız gerekenden daha iyi yazılmış. Örneğin: http://docs.ansible.com/ansible/latest/systemd_module.html https://docs.saltstack.com/en/latest/ref/states/all/salt.states.service.html

Mimari açıdan bakıldığında, bir web sunucusunu yönetmek için bir miktar rasgele kod bulundurmak kabuslardır. Hizmetleri yönetmediğiniz sürece, yalnızca kodunuz ne yapar? Ama tahminim ki para yatırma (ya da kubernetes ya da ...) yazmamışsın


2
Dil Java'dır ve yöntem, bağımsız bir Jersey uygulamasında bir bozkır gömülü sunucu başlatmak için tasarlanmıştır. Size çok fazla içerik vermediğim için yorumunuzun doğruluğunu suçlayamam, ancak ifadenizi yaparken çok düşündünüz. Sunucuyu başlatmak için iskeleye veya grizzly çağıran bir yönteme sahip olmak gayet iyi.
John Calcote

1
API sağlamak için kendi kendine barındırılan HTTP sunucusunu içeren milyonlarca işletme uygulaması vardır. Ve bunların hepsi bir olması, güvenlik ayarlarını vs. kullanmak üzere hangi liman, üzerinde bağlamak için aslında kullandıkları kütüphane kurar ve bu hangi arayüz olarak bilgi sağlar bazı çok basit kod gerekir startServerişlevi ya da bir şey nadir fakat benzer . Bu, nitty-gritty düşük seviye detaylarını yazacağınız anlamına gelmez.
Voo
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.