Neden Java / Spring üzerinden Scala / Lift kullanmalıyım? [kapalı]


151

Bu sorunun biraz açık olduğunu biliyorum ama Scala / Lift'e Java / Spring'e bir alternatif olarak bakıyorum ve Scala / Lift'in bunun üzerinde gerçek avantajları olduğunu merak ediyorum. Benim bakış açımdan ve tecrübelerime göre, Java Ek Açıklamaları ve Bahar, bir uygulama için yapmanız gereken kodlama miktarını gerçekten en aza indirir. Scala / Lift bunu geliştirir mi?


Soru çok eski. Ama şimdi soru “Scala / Play'i XYX üzerinden neden kullanmalıyım” olacaktır ve bunun birçok iyi nedeni vardır. Play'e geçtim ve asla geriye bakmadım.
Jus12

Yanıtlar:


113

Scala ve Java'da eşit derecede rahat olduğumuzu varsayalım ve Bahar veya Asansör ile ilgili olanlar dışında (büyük) dil farklılıklarını görmezden gelelim.

Spring ve Lift olgunluk ve hedefler bakımından neredeyse taban tabana zıttır.

  • Bahar, Lift'ten yaklaşık beş yaş büyük
  • Asansör monolitiktir ve sadece ağı hedefler; Bahar modülerdir ve hem web hem de "normal" uygulamaları hedefler
  • Spring, çok sayıda Java EE özelliğini destekler; Lift bu şeyleri yok sayar

Bir cümleyle, Bahar ağır ve Lift hafiftir. Yeterli kararlılık ve kaynaklarla bunu kafasına çevirebilirsiniz, ancak her ikisine de çok ihtiyacınız olacaktır .

İşte her iki çerçeveyle çalıştıktan sonra aklımda kalan somut farklılıklar. Bu, bir şekilde derleyemediğim kapsamlı bir liste değil. Benim için en ilginç görünen şey ...

  1. Felsefeyi görüntüle

    Asansör snippet / eylem yöntemlerine bazı görünüm materyalleri yerleştirmeyi teşvik eder. Snippet kodu özellikle programlı olarak oluşturulmuş form öğeleri, <div>s, <p>s vb.

    Bu güçlü ve kullanışlıdır, özellikle Scala yerleşik bir dil düzeyinde XML moduna sahip olduğundan. Parantez içindeki değişken bağlamalar da dahil olmak üzere Scala yöntemleri içinde XML satır içi yazılabilir. Bu, çok basit XML hizmetleri veya hizmet örnekleri için keyifli olabilir - şablonlar veya çok fazla görevli yapılandırması olmadan tek bir görkemli kısa dosyada bir HTTP yanıt eylemleri grubunu patlatabilirsiniz. Dezavantajı karmaşıklıktır. Ne kadar ileri gideceğinize bağlı olarak, görünüm ve mantık arasındaki endişelerin bulanık bir şekilde ayrılması veya ayrılma olmaması.

    Aksine, webapps için Spring'in düzenli kullanımı, görünüm ve diğer her şey arasında güçlü bir ayrım yapılmasını zorunlu kılar. Bence Spring birkaç şablon motorunu destekliyor, ancak JSP'yi sadece ciddi bir şeyde kullandım. JSP ile Lift'ten ilham alan bir "bulanık MVC" tasarımı yapmak delilik olacaktır. Bu, sadece okuma ve anlama zamanının çok büyük olabileceği daha büyük projelerde iyi bir şeydir.

  2. Nesne İlişkisel Eşleyici Seçenekleri

    Lift'in yerleşik ORM'si "Mapper" dır. "Record" adında yeni bir alternatif var, ancak bence hala alfa öncesi sayılıyor. LiftWeb Kitabının hem Mapper hem de JPA kullanımıyla ilgili bölümleri vardır.

    Asansörün CRUDify özelliği olduğu gibi, sadece Eşleyici'ye (ve JPA) ile çalışır serin.

    Tabii ki, Spring standart ve / veya olgun veritabanı teknolojilerinin bir grubunu destekler . Operatif kelime orada "destekler". Teorik olarak, herhangi bir Java ORM'yi Lift ile birlikte kullanabilirsiniz, çünkü Scala'dan rasgele Java kodu çağırabilirsiniz. Ancak Lift yalnızca Mapper'ı ve (çok daha az ölçüde) JPA'yı gerçekten destekler. Ayrıca, Scala'da önemsiz olmayan Java koduyla çalışmak şu anda istendiği kadar kesintisiz değil; bir Java ORM kullanarak, kendinizi hem Java hem de Scala koleksiyonlarını her yerde kullanırken veya tüm koleksiyonları Java bileşenlerinin içine ve dışına dönüştürürken bulacaksınız.

  3. Yapılandırma

    Lift uygulamaları hemen hemen tamamen uygulama genelinde bir "Boot" sınıfı yöntemiyle yapılandırılır. Başka bir deyişle, yapılandırma Scala kodu üzerinden yapılır. Bu, kısa yapılandırmaları olan projeler için mükemmeldir ve yapılandırmayı yapan kişi Scala'yı rahat bir şekilde düzenlediğinde.

    Yay, konfigürasyon açısından oldukça esnektir. Çok sayıda conf seçeneği XML yapılandırması veya ek açıklamalar aracılığıyla yönlendirilebilir.

  4. belgeleme

    Lift'in belgeleri genç. Spring'in belgeleri oldukça olgun. Yarışma yok.

    Spring'in belgeleri zaten iyi organize edilmiş ve bulunması kolay olduğundan, Lift için bulduğum belgeleri inceleyeceğim. Temel olarak Lift belgelerinin 4 kaynağı vardır: LiftWeb Kitabı , API Belgeleri , LiftWeb'in Google grubu ve " Başlarken ". Orada da güzel bir kod örnekleri paketi, ama ben onlara "belgeler" per demezdim.

    API dokümanları eksik. LiftWeb Kitabı ağaçlarda yayınlanmıştır, ancak çevrimiçi olarak da ücretsiz olarak mevcuttur. Kesinlikle didaktik tarzı zaman zaman beni rahatsız etmesine rağmen, gerçekten yararlıdır. Bu biraz öğretici uzun ve sözleşme kısa. Bahar, Asansör eksik olan uygun bir el kitabına sahiptir.

    Ancak Lift'in güzel örnekleri var. Asansör kodunu ve örnek kodu okumaktan memnunsanız (ve zaten Scala'yı iyi biliyorsanız), işleri oldukça kısa bir sırayla yapabilirsiniz.

Her iki çerçeve de ilgi çekicidir. İkisini de seçebileceğiniz ve iyi yapabileceğiniz çok çeşitli uygulamalar var.


10
İyi bir cevap, buna katılmıyorum bir nokta: Bahar ağır olmak. Geniş bir iyi APIS yelpazesine sahiptir ve iyi bir sonuç elde etmek için gerekli yapısal çalışma yöntemlerini uygular, ancak orijinal olarak değiştirdiği J2EE şeyleriyle karşılaştırıldığında çok daha hafif bir çözümdür. Tabii ki "hafiflik" bakanın gözündedir, bu yüzden bu kesinlikle öznel bir argüman. O zaman sadece 2 sentim.
Brian

3
İyi cevap, çok objektif. Lift, çok aptalca görünen çok akıllı şeyler yapar. Sayfa mantığını arka uca taşımak, HTML'yi skala koduna karıştırmak, sayfa şablonundaki kontrol etiketlerinden daha kötüdür. Bunu neden yaptığını bilmiyorum, belki de Scala'nın XML'i şaşırtıcı derecede hızlı işlemesi gerektiğini düşünüyorlar. "Kesin Asansör kılavuzu" şimdiye kadar okuduğum en kötü teknik kitap.
Sawyer

Asansörü istediğim kadar tanımadım. Size göre bir xml dosyasından ayarları okuyan önyükleme nesnesi için bir sarıcı yapmak ne kadar zor olurdu? İlk izlenimim scala xml'yi kutudan çok iyi işlediğinden, son derece zor olmayacağı.
Ape-inago

Sawyer, HTML'yi scala koduna karıştırabilmeniz gerektiği anlamına gelmiyor. Parçacıkları akıllı bir şekilde kullanmak HTML ve Scala kodunu ayırır. Ama hey, kontrol etiketlerini kullanmaya devam et;)
Alebon

1
@Dan, Lift'in bunu ilk yazdığınızdan iki kat daha eski olduğu konusunda herhangi bir güncelleme var mı?
Pacerier

229

Dan LaRocque'un cevabına kesinlikle katılmıyorum demeliyim.

Asansör yekpare değildir. Ayrık elemanlardan oluşur. J / EE elemanlarını görmezden gelmez, JNDI, JTA, JPA, vb. Gibi özellikleri destekler. J / EE'nin bu elemanlarını kullanmaya zorlanmamanız Lift'in modüler tasarımının güçlü bir göstergesidir.

  • Lift'in görüş felsefesi "geliştirici karar versin" dir. Lift, görünümde herhangi bir mantık koduna izin vermeyen bir şablonlama mekanizması, Scala kodunu ve Scala'nın XML değişmezlerini yürütmeye dayalı bir görünüm mekanizması ve Scalate'e dayalı bir görünüm mekanizması sunar . XML şablonlama mekanizmasını seçerseniz, işaretlemenin iş mantığınıza ne kadar (varsa) ait olduğunu seçersiniz. Lift'in görünüm ayrımı, Spring'in sunduğu her şeyden daha güçlüdür çünkü Lift'in XML şablonlarında herhangi bir iş mantığını ifade edemezsiniz.
  • Lift'in Nesnesi ↔ Kalıcılık felsefesi "geliştirici karar versin" dir. Lift, ActiveRecord tarzı nesne ilişkisel eşleyicisi olan Mapper'a sahiptir. Küçük projeler için işi yapar. JPA desteğini kaldırın. Lift, ilişkisel veritabanlarının içine ve dışına NoSQL depolarına girip çıkmayı destekleyen bir Kayıt soyutlamasına sahiptir (Lift, CouchDB ve MongoDB için yerel destek içerir, ancak adaptör katmanları birkaç yüz kod satırıdır; başka bir şey, bunu elde etmek için çok fazla iş değil.) Temel olarak, Lift Web Framework nesnelerin bir oturumda nasıl gerçekleştiğine bağlı değildir. Ayrıca, oturum ve istek döngüleri açıktır, öyle ki istek / yanıt döngüsüne işlem kancaları eklemek basittir.
  • Lift'in felsefesi "sunucu ekibinin birden fazla dili değil, bir dili bilmesi gerekiyor." Bu, konfigürasyonun Scala üzerinden yapıldığı anlamına gelir. Bu, esnek yapılandırma seçenekleri oluşturmak için Java'nın dil yapılarının% 40'ını XML sözdiziminde uygulamak zorunda olmadığımız anlamına gelir. Bu, derleyici sözdiziminin ve türün yapılandırma verilerini kontrol ettiği, böylece çalışma zamanında garip XML ayrıştırma veya yanlış veri elde edemeyeceğiniz anlamına gelir. Başka bir deyişle, kullandığınız kitaplığa göre kullandığınız ek açıklamaların ayrıntılarını anlayan IDE'lere sahip olmanız gerekmez.
  • Evet, Lift'in belgeleri güçlü noktası değil.

Yukarıdakilerin söylendiği gibi, Lift'in tasarım felsefesi hakkında konuşalım.

Lift yazmaya başlamadan önce Web Framework Manifestosu'nu yazdım . Büyük ölçüde ve bildiğim diğer tüm web çerçeveleri için geçerli olandan daha yüksek derecede, Lift bu hedeflere ulaşır.

Özünde asansör, nesne sarmalayıcılarını HTTP İsteği'nin etrafına yerleştirmek yerine HTTP istek / yanıt döngüsünü soyutlamaya çalışır. Pratik düzeyde, bu, kullanıcının yapabileceği her işlemin (form öğelerini gönderme, Ajax vb. Yapma) tarayıcıda bir GUID ve sunucudaki bir işlevle temsil edildiği anlamına gelir. GUID, bir HTTP isteğinin parçası olarak sunulduğunda, işlev sağlanan parametrelerle uygulanır (çağrılır). GUID'leri tahmin etmek zor ve oturuma özgü olduğu için, tekrar saldırıları ve birçok parametre müdahalesi saldırısı, Lift de dahil olmak üzere diğer web çerçevelerinin çoğundan çok daha zordur. Ayrıca, geliştiricilerin daha verimli oldukları anlamına gelir, çünkü bir HTTP isteğinin paketlenmesi ve paketinin açılması yerine kullanıcı eylemlerine ve kullanıcı eylemleriyle ilişkili iş mantığına odaklanırlar.

ajaxButton("Accept", () => {request.accept.save; 
                            SetHtml("acceptrejectspan", <span/>}) ++ 
ajaxButton("Reject", () => {request.reject.save; 
                            SetHtml("acceptrejectspan", <span/>})

Bu kadar basit. FriendRequest işlev oluşturulduğunda kapsamda olduğundan, işlev kapsam üzerinde kapanır ... arkadaşlık isteğinin birincil anahtarını açığa çıkarmaya veya başka bir şey yapmaya gerek yoktur ... sadece düğmenin metnini tanımlayın ( yerelleştirilebilir veya bir XHTML şablonundan çekilebilir veya yerelleştirilmiş bir şablondan çekilebilir) ve düğmeye basıldığında yürütülecek işlev. Lift, GUID'in atanmasına, Ajax çağrısının ayarlanmasına (jQuery veya YUI aracılığıyla ve evet, kendi favori JavaScript kitaplığınızı ekleyebilir), geri çekmelerle otomatik yeniden denemeler gerçekleştirmeye, Ajax isteklerini sıralayarak bağlantı açlığını önlemeye vb.

Bu nedenle, Lift ve Spring arasındaki büyük bir fark, Lift'in fonksiyonla ilişkili GUID felsefesinin çok daha iyi güvenlik ve daha iyi geliştirici üretkenliği gibi iki avantajı olmasıdır. GUID -> İşlev ilişkilendirmesinin çok dayanıklı olduğu kanıtlanmıştır ... aynı yapı normal formlar, ajax, kuyruklu yıldız, çok sayfalı sihirbazlar vb.

Bir sonraki ana Lift parçası, yüksek seviyeli soyutlamaları olabildiğince uzun süre tutuyor. Sayfa oluşturma tarafında, sayfanın XHTML öğeleri olarak oluşturulması ve sayfanın yanıt akışından hemen öncesine kadar XHTML olarak tutulması anlamına gelir. Avantajlar, siteler arası komut dosyası yazma hatalarına karşı direnç, CSS etiketlerini sayfa oluşturulduktan sonra sayfanın altına ve komut dosyalarını sayfanın altına taşıma ve hedef tarayıcıya göre sayfayı yeniden yazma yeteneğidir. Giriş tarafında, URL'ler, parametreleri (hem sorgu hem de yol parametreleri) tür güvenli bir şekilde ayıklamak için yeniden yazılabilir, yüksek düzeyde, güvenlikle kontrol edilen veriler, istek döngüsünün çok erken aşamalarında işlenebilir. Örneğin, bir REST isteğinin servisinin nasıl tanımlanacağı aşağıda açıklanmıştır:

  serve {
    case "api" :: "user" :: AsUser(user) :: _ XmlGet _ => <b>{user.name}</b>
    case "api" :: "user" :: AsUser(user) :: _ JsonGet _ => JStr(user.name)
  }

Scala'nın yerleşik kalıp eşleşmesini kullanarak, gelen bir isteği eşleştiriyoruz, yolun üçüncü bölümünü çıkartıyoruz ve bu değere karşılık gelen Kullanıcıyı alıyoruz ve hatta erişim kontrol kontrolleri uyguluyoruz (mevcut oturumun veya isteğin verilen erişim için izinleri var mı? Kullanıcı kaydı). Bu nedenle, User örneği uygulama mantığına çarptığında, denetlenir.

Bu iki temel parça ile Lift, güvenlik açısından muazzam bir avantaja sahiptir. Lift'in güvenliğinin özellikleri engellemeyen büyüklüğü hakkında fikir vermek için Yahoo! için güvenlik yapan Rasmus Lerdorg ! FourSquare (Lift poster-çocuk sitelerinden biri) hakkında şunları söylemişti:

Dört yıldız için @ dört yıldız - Bir süre içinde 1. site Tek bir güvenlik sorunu (bulabildiğim) yoktu iyi bir göz attım - http://twitter.com/rasmus/status/5929904263

O zaman, FourSquare'in kod üzerinde çalışan bir mühendisi vardı (@harryh bir süper dahi değil) ve ana odak noktası haftalık trafik ikilemi ile başa çıkarken FourSquare'in PHP sürümünü yeniden yazmaktı.

Lift'in güvenlik odağının son kısmı Site Haritası'dır. Birleşik bir erişim kontrolü, sitede gezinme ve menü sistemidir. Geliştirici, Scala kodu (örn. If(User.loggedIn _)Veya If(User.superUser _)) kullanarak her sayfa için erişim kontrol kurallarını tanımlar ve bu erişim kontrol kuralları herhangi bir sayfa oluşturma başlamadan önce uygulanır. Bu, Spring Security'ye çok benzer, ancak projenin başından itibaren pişirilir ve erişim kontrol kuralları uygulamanın geri kalanıyla birleştirilir, böylece URL'ler olduğunda XML'deki güvenlik kurallarını güncelleme işlemine sahip olmanız gerekmez değişikliği veya erişim denetimi değişikliğini hesaplayan yöntemler.

Özetlemek gerekirse, Lift'in tasarım felsefesi size erişim kontrolü, OWASP ilk 10 güvenlik açığına karşı direnç, Spring'den çok daha iyi Ajax desteği ve çok daha yüksek geliştirici üretkenliği gibi avantajlar sunar.

Ancak Lift, etrafınızdaki herhangi bir web çerçevesinin en iyi Comet desteğini de sağlar. Bu nedenle Novell, Pulse ürünlerine güç vermek için Lift'i seçti ve Novell'in Lift hakkında söyledikleri:

Lift, bir geliştirici olarak büyük resme odaklanmanızı sağlayan bir web çerçevesi türüdür. Yerleşik Kuyruklu yıldız desteği gibi güçlü, etkileyici yazım ve daha üst düzey özellikler, sıhhi tesisat yerine inovasyona odaklanmanızı sağlar. Novell Pulse gibi zengin, gerçek zamanlı bir web uygulaması oluşturmak, kapakların altında Lift'in gücüne sahip bir çerçeve gerektirir.

Yani, Lift sadece başka bir MVC çerçevesi değildir. Arkasında çok iyi olgunlaşan bazı temel tasarım ilkelerine sahip bir çerçeve. Güvenlik ve geliştirici verimliliğinin iki avantajını sunan bir çerçeve. Asansör, katmanlar halinde yerleşik bir çerçevedir ve geliştiriciye ihtiyaçlarına göre doğru seçenekler sunar ... görünüm oluşturma seçenekleri, kalıcılık seçenekleri vb.

Scala ve Lift, geliştiricilere, Spring'i oluşturan XML, ek açıklamalar ve diğer deyimlerden daha iyi bir deneyim sunar.


2
Blog.lostlake.org/index.php?/archives/16-Web-Framework-Manifesto.html dosyasının arşivlenmiş bir sürümünü replay.web.archive.org/20070220231839/http://blog.lostlake.org/… adresinde bulabilirsiniz.
Alan Hecht

1
Beni MongoDB yerel desteğinde bulundun ... Ben
Eran Medan

8
90'lı yılların ortalarından beri webapps yazıyorum. Perl, Java, Seam, JSP ve diğerlerini topluyorum. İlkbaharı kullanan tanıdığım herkes, yapılandırmaları ve bağımlılıkları doğru hale getirme zorluğu, maven kabusları vb. Şikayet ediyor. Lift'i birkaç hafta önce bir projede kullanmaya başladım ve kesinlikle şaşırdım. İşlerin neredeyse çaba sarf etmeden çalıştığı yerlerde kullandığım ilk çerçeve (ve dil). Uygulamamda şimdiye kadar düzinelerce özellik yazdım ve ne kadar çabuk doğru bulduğuma sürekli şaşırdım ... sucky dokümanlar ve sınırlı bir Scala anlayışı ile bile. Görmek inanmaktır.
Tony K.

@TonyK .: elbette Spring ağırdır, ancak web uygulaması çok daha sonra değiştirilirse, Bahar ile yeniden düzenleme / genişletme çok daha kolay olduğu için ödeme yapar. IMHO, duruma göre değişir. Grails gibi başka bazı çerçeveleri de küçük projelerde kullandım ve bence bunun için mükemmel - ama bir şey daha sonra değişecek, Bahar ile giderdim.
Hoàng Long

7
@ HoàngLong Yazılım evriminin zorluğuna birçok yaklaşım vardır. Basitçe deneyimlerimi söylüyorum: Java, üzerine inşa edilen çerçeveler gibi bir dil olarak yaşını gösteriyor. Tüm kazan plakası ve konfigürasyon çılgınlığı olmadan daha etkileyici ve güçlü şeylere dönüşme zamanı.
Tony K.

11

Oyun çerçevesini kontrol etmenizi öneririm, çok ilginç fikirleri var ve Java ve Scala'daki gelişimi destekliyor


2
Play'e baktım. Bunu tavsiye etmek için yerleşik sınıf yeniden yükleme dışında bir şey görmedim ve ücretsiz Scala JRebel lisansı ile bunu Lift ile elde edersiniz.
Tony K.

10

Sadece eğlence için. Ve yeni programlama yaklaşımlarını öğrenmek uğruna.


10

Spring MVC'nin büyük bir hayranı değil, yakın zamanda bir web projesi için Lift'i güçlü bir şekilde araştırdım. En son sürümleri kullanmadım, ancak Spring MVC'nin önceki sürümleri bir web uygulamasını çalıştırmak için birçok çembere atlamanızı sağladı. Lift'in oturuma bağımlı olabileceğini ve düzgün çalışması için 'yapışkan oturumlar' gerektirdiğini görene kadar neredeyse Lift'te satıldım. Http://exploring.liftweb.net/master/index-9.html#sec:Session-Management adresinden alıntı

Standart bir oturum çoğaltma teknolojisi olana kadar, uygulamanızı “yapışkan oturum” kullanarak kümeleyebilirsiniz. HTTP oturumu ile ilgili tüm isteklerin aynı küme düğümü tarafından işlenmesi gerektiği ölçüsü

Bu yüzden bir Oturum gerekli olduğunda, kullanıcının bu düğüme sabitlenmesi gerekir. Bu, akıllı yük dengeleme ihtiyacını yaratır ve Lift'in benim durumumda bir çözüm olmasını engelleyen ölçeklendirmeyi etkiler. Sonunda http://www.playframework.org/ 'i seçtim ve çok memnun oldum . Oyun şu ana kadar istikrarlı ve güvenilir ve çalışması çok kolay.


7

Ben vermedi bu kişisel deneyimlerinden değil bu yüzden, bir Java arka plandan Lift ve Scala gelmek ama birçok Kaldırma geliştiricileri Scala Java çok daha özlü ve etkili bir dil olarak görüyorum biliyorum.


3

Bilginizi genişletmek her zaman faydalı bir çabadır :) Scala öğrenmeye yeni başladım, normal Java'yı nasıl yazdığımı etkiliyor ve şimdiye kadar çok faydalı olduğunu söyleyebilirim.


3

Dünyanızı bir döngü için tamamen atmaktan nefret ediyorum. Ama tek bir uygulamada Scala, Java, Lift, Spring kullanabilirsiniz ve bir sorun olmamasını sağlayabilirsiniz.


0

Benim düşünceme göre, hayal gücü önemlidir.

Bir uygulama yazmak istediğinizi düşünelim. İyi bir geliştiriciyseniz, uygulama zaten aklınızda oluşturulmalıdır. Bir sonraki adım, kod yoluyla nasıl çalıştığını keşfetmek. Bunu yapmak için, hayal edilen uygulamayı gerçek dünya uygulamasına çeviren bir işlevden geçirmeniz gerekir. Bu işlev bir programlama dilidir. Yani

Real app = programming language (imagined app)

Bu nedenle dil seçimi önemlidir. Çerçeve de öyle. Burada neyi seçeceğiniz konusunda size tavsiyede bulunacak bir ton akıllı insan var, ama nihayetinde hayal gücünüzü en iyi şekilde çeviren dil / çerçeve seçiminiz olmalı. Yani her ikisiyle de prototip ve seçiminizi yapın.

Bana gelince, yavaş yavaş Scala ve Lift'i öğreniyorum ve çok seviyorum.


0

Ama asıl sorun, yayı asansörle karşılaştıramayacağımızdır. Asansör temelde UI çerçevesi, Spring ise DI çerçevesi olarak kullanılır.
Eğer asansör kullanabilirsiniz emin arka uç çok var web uygulaması geliştiriyorsanız.
ama bazı dizi backend olan gelişmekte olan web uygulaması ve definelty bahar gitmek gerekir.

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.