Web'de oluşturma

Uygulamalarımızda mantık ve oluşturmayı nerede uygulamalıyız? Sunucu Tarafında Oluşturma'yı kullanmalı mıyız? Sıvı alımı ne olacak? Şimdi birkaç yanıt bulalım!

Geliştiriciler olarak sık sık uygulamalarımızın tüm mimarisini etkileyecek kararlarla karşılaşıyoruz. Web geliştiricilerin alması gereken temel kararlardan biri, mantığı ve oluşturma sürecini uygulamalarında nereye yerleştireceğidir. Web sitesi oluşturmanın birçok farklı yolu olduğundan bu zor olabilir.

Bu alanla ilgili anlayışımızı, Chrome'da son birkaç yılda büyük sitelerle yaptığımız konuşmalar belirler. Genel olarak, geliştiricilerin tam yenileme yaklaşımı yerine sunucu tarafı oluşturmayı veya statik oluşturmayı düşünmelerini öneririz.

Bu kararı verdiğimizde hangi mimarileri seçeceğimizi daha iyi anlamak için her bir yaklaşımı sağlam bir şekilde anlamamız ve onlar hakkında konuşurken kullanacağımız tutarlı terminolojiyi bilmemiz gerekiyor. Bu yaklaşımlar arasındaki farklar, performans açısından web'de oluşturma işleminin avantajlarını görmenize yardımcı olur.

Terminoloji

Görüntü Oluşturma

  • Sunucu tarafı oluşturma (SSR): İstemci tarafında veya evrensel bir uygulamayı sunucuda HTML'ye oluşturma.
  • İstemci tarafı oluşturma (CSR): DOM'yi değiştirmek için bir uygulamayı JavaScript ile tarayıcıda oluşturma.
  • Yeniden kullanma: Sunucu tarafından oluşturulan HTML'nin DOM ağacını ve verilerini yeniden kullanacak şekilde JavaScript görünümlerini istemcide"başlatma".
  • Önceden işleme: Derleme sırasında istemci tarafı uygulamayı, uygulamanın başlangıç durumunu statik HTML olarak yakalamak için çalıştırma.

Performans

Sunucu tarafında oluşturma

Sunucu tarafı oluşturma, gezinmeye yanıt olarak sunucudaki bir sayfa için tam HTML'yi oluşturur. Bu işlem, istemcide veri getirme ve şablon oluşturma işlemleri tarayıcı yanıt almadan önce yapıldığından, bu işlemler için ek gidiş gelişleri önler.

Sunucu tarafı oluşturma genellikle hızlı bir FCP üretir. Sayfa mantığının çalıştırılması ve sunucuda oluşturulması, istemciye çok fazla JavaScript gönderilmesini önlemeyi mümkün kılar. Bu, sayfa yükleme sırasında ana iş parçacığı aynı sıklıkta engellenmeyeceği için sayfanın TBT'sini azaltmaya yardımcı olur. Bu da daha düşük INP'ye neden olabilir. Ana iş parçacığı daha seyrek engellendiğinde kullanıcı etkileşimlerinin daha kısa sürede gerçekleşme fırsatı olur. Sunucu tarafı oluşturma ile gerçekten yalnızca kullanıcının tarayıcısına metin ve bağlantı gönderdiğiniz için bu mantıklıdır. Bu yaklaşım, geniş bir cihaz ve ağ koşulları yelpazesi için iyi bir şekilde çalışabilir ve akış dokümanı ayrıştırma gibi ilgi çekici tarayıcı optimizasyonları sunar.

FCP ve TTI'yı etkileyen sunucu tarafı oluşturma ve JS yürütme işlemlerini gösteren şema.

Sunucu tarafında oluşturma sayesinde kullanıcıların, sitenizi kullanmadan önce CPU'ya bağlı JavaScript'in çalışmasını beklemek zorunda kalmazlar. Üçüncü taraf JS'den kaçınılamasa bile, kendi birinci taraf JavaScript maliyetlerinizi azaltmak için sunucu tarafı oluşturmayı kullanmak, geri kalan işlemler için daha fazla bütçe elde etmenizi sağlayabilir. Bununla birlikte, bu yaklaşımın potansiyel bir dengesi söz konusudur: Sunucuda sayfa oluşturmak zaman alır ve bu da daha yüksek bir TTFB ile sonuçlanabilir.

Sunucu tarafı oluşturmanın uygulamanız için yeterli olup olmaması, büyük ölçüde oluşturduğunuz deneyim türüne bağlıdır. Sunucu tarafında oluşturmanın mı yoksa istemci tarafında oluşturmanın mı doğru uygulamalarının kullanılacağı konusunda uzun süredir devam eden bir tartışma vardır, ancak bazı sayfalar için sunucu tarafı oluşturmayı kullanmayı seçebileceğinizi unutmamak önemlidir. Bazı siteler, karma oluşturma tekniklerini başarılı bir şekilde kullanmaktadır. Netflix sunucusu, nispeten statik açılış sayfalarını oluşturur ve etkileşim ağırlıklı sayfalar için JS'yi önceden getirerek bu ağır istemci tarafından oluşturulan sayfaların hızlı yüklenme şansını artırır.

Birçok modern çerçeve, kitaplık ve mimari aynı uygulamanın hem istemcide hem de sunucuda oluşturulmasına olanak tanır. Bu teknikler, sunucu tarafı oluşturmada kullanılabilir. Ancak oluşturma işleminin hem sunucuda hem de istemcide gerçekleştiği mimarilerin, oldukça farklı performans özellikleri ve ödünleri olan kendi çözüm sınıfları olduğu unutulmamalıdır. React kullanıcıları, sunucu DOM API'lerini veya sunucu tarafı oluşturma için Next.js gibi bunların üzerinde oluşturulan çözümleri kullanabilir. Vue kullanıcıları, Vue'nun sunucu tarafı oluşturma kılavuzuna veya Nuxt'a bakabilir. Angular, Universal'a sahiptir. Ancak en popüler çözümlerde bir çeşit hidrasyon uygulanır. Bu nedenle, bir araç seçmeden önce kullanılan yaklaşımı göz önünde bulundurun.

Statik oluşturma

Statik oluşturma, derleme anında gerçekleşir. İstemci tarafı JS miktarının sınırlı olduğu varsayıldığında bu yaklaşım hızlı bir FCP, ayrıca daha düşük TBT ve INP sunar. Sunucu tarafı oluşturmanın aksine, bir sayfanın HTML'sinin sunucuda dinamik olarak oluşturulması gerekmediğinden, tutarlı şekilde hızlı bir TTFB sağlamayı da başarır. Statik oluşturma, genellikle her URL için önceden ayrı bir HTML dosyası oluşturulması anlamına gelir. Önceden oluşturulan HTML yanıtları sayesinde statik oluşturmalar, uç önbelleğe alma özelliğinden yararlanmak için birden fazla CDN'ye dağıtılabilir.

FCP ve TTI'yı etkileyen statik oluşturma ve isteğe bağlı JS yürütme işlemlerini gösteren şema.

Statik oluşturma çözümleri farklı şekillerde ve boyutlarda olabilir. Gatsby gibi araçlar, geliştiricilerin uygulamalarının bir derleme adımı olarak değil, dinamik olarak oluşturulduklarını hissetmelerini sağlamak için tasarlanmıştır. 11ty, Jekyll ve Metalsmith gibi statik site oluşturma araçları statik yapılarını benimseyerek daha şablon odaklı bir yaklaşım sunar.

Statik oluşturmanın dezavantajlarından biri, mümkün olan her URL için ayrı HTML dosyalarının oluşturulmasıdır. Bu URL'lerin ne olacağını önceden tahmin edemiyorsanız veya çok sayıda benzersiz sayfası olan siteler için bu zor, hatta olanaksız olabilir.

React kullanıcıları Gatsby, Next.js statik dışa aktarma veya Navi hakkında bilgi sahibi olabilir. Tüm bunlar, bileşenleri kullanarak sayfa oluşturmayı kolaylaştırır. Bununla birlikte, statik oluşturma ve önceden oluşturma arasındaki farkı anlamak önemlidir: Statik oluşturulan sayfalar, istemci tarafında çok fazla JavaScript yürütmeye gerek kalmadan etkileşimlidir. Önceden oluşturma ise sayfaların gerçekten etkileşimli olması için istemcide başlatılması gereken Tek Sayfalık Uygulamanın FCP'sini iyileştirir.

Belirli bir çözümün statik oluşturma mı yoksa önceden oluşturma mı olduğundan emin değilseniz JavaScript'i devre dışı bırakmayı ve test etmek istediğiniz sayfayı yüklemeyi deneyin. Statik olarak oluşturulan sayfalarda, işlevlerin çoğu JavaScript etkinleştirilmeden var olmaya devam eder. Önceden işlenmiş sayfalar için bağlantılar gibi bazı temel işlevler bulunmaya devam edebilir ancak sayfanın çoğu durağan olur.

Yararlı bir diğer test de Chrome Geliştirici Araçları'nda ağ sınırlamayı kullanmak ve bir sayfa etkileşimli hale gelmeden önce ne kadar JavaScript indirilmiş olduğunu gözlemlemektir. Önceden işlemenin etkileşimli hale gelmesi için genellikle daha fazla JavaScript gerekir ve bu JavaScript, statik oluşturma tarafından kullanılan progresif geliştirme yaklaşımından daha karmaşık olma eğilimindedir.

Sunucu tarafı oluşturma ve statik oluşturma karşılaştırması

Sunucu tarafı oluşturma sihirli bir değnek değildir. Dinamik yapısı nedeniyle yüksek işlem ek maliyetlerine neden olabilir. Birçok sunucu tarafı oluşturma çözümü, erken temizlik yapmaz, TTFB'yi geciktirebilir veya gönderilen verilerin iki katına çıkabilir (örneğin, istemcideki JavaScript tarafından kullanılan satır içi durum). React'te renderToString(), eşzamanlı ve tek iş parçacıklı olduğundan yavaş olabilir. Akışı destekleyen Newer React sunucu DOM API'leri, HTML yanıtının ilk kısmını tarayıcıya daha kısa sürede ulaştırabilir ve diğer kısmı sunucuda oluşturulmaya devam eder.

Sunucu tarafı oluşturma işleminin "doğru" olmasını sağlamak için bileşen önbelleği için bir çözüm bulup geliştirmeyi, bellek tüketimini yönetmeyi, hatırlatma tekniklerini uygulamayı ve diğer konuları kapsayabilir. Genellikle aynı uygulamayı bir kez istemcide, bir kez de sunucuda olmak üzere birden çok kez işliyor/yeniden oluşturuyorsunuz. Sunucu tarafı oluşturmanın bir öğenin daha erken gösterilmesini sağlaması, yapmanız gereken işin aniden azalacağı anlamına gelmez. Sunucu tarafından oluşturulan bir HTML yanıtı istemciye ulaştıktan sonra istemci üzerinde çok iş yapmanız durumunda, bu durum yine de web siteniz için daha yüksek TBT ve INP sağlayabilir.

Sunucu tarafı oluşturma, her URL için isteğe bağlı HTML üretir, ancak statik olarak oluşturulmuş içerik yayınlamaktan daha yavaş olabilir. Ek aşamaya katkıda bulunabilirseniz sunucu tarafı oluşturma ve HTML önbelleğe alma, sunucunun oluşturma süresini önemli ölçüde kısaltabilir. Sunucu tarafı oluşturmanın avantajı, daha fazla "canlı" veri çekme ve statik oluşturmada mümkün olandan daha eksiksiz bir istek kümesine yanıt verebilme yeteneğidir. Kişiselleştirme gerektiren sayfalar, statik oluşturmada iyi sonuç vermeyecek istek türünün somut bir örneğidir.

PWA oluştururken sunucu tarafı oluşturma ilginç kararlar da sağlayabilir: Tam sayfa hizmet çalışanı önbelleğe almayı kullanmak mı yoksa sadece tek tek içerik parçalarını sunucu oluşturmak mı daha iyidir?

İstemci tarafı oluşturma

İstemci tarafı oluşturma, sayfaların JavaScript ile doğrudan tarayıcıda oluşturulması anlamına gelir. Tüm mantık, veri getirme, şablon oluşturma ve yönlendirme işlemleri sunucu yerine istemcide gerçekleştirilir. Etkili sonuç, daha fazla verinin sunucudan kullanıcının cihazına aktarılması ve bu verinin, kendine özgü dengeleriyle birlikte gelmesidir.

İstemci tarafı oluşturma, mobil cihazlarda hızlı ve kolay bir şekilde oluşturulabilir. Minimum düzeyde iş yapılırsa istemci tarafı oluşturma, yalın sunucu tarafı oluşturma performansına yaklaşarak dar bir JavaScript bütçesini koruyabilir ve olabildiğince az gidiş-dönüş ile değer sağlayabilir. <link rel=preload> ile kritik komut dosyaları ve veriler daha erken teslim edilebilir. Böylece ayrıştırıcı sizin için daha kısa sürede çalışır. Başlangıçtaki ve sonraki gezinmelerin anlık hissettirmesi için PRPL gibi kalıplar da değerlendirilmeye değer.

FCP ve TTI&#39;yı etkileyen istemci taraflı oluşturma işlemini gösteren şema.

İstemci tarafı oluşturmanın birincil dezavantajı, gereken JavaScript miktarının uygulama büyüdükçe artma eğiliminde olmasıdır. Bu da sayfanın INP'sini olumsuz etkileyebilir. İşlem gücü için rekabet eden ve bir sayfanın içeriğinin oluşturulabilmesi için genellikle işlenmesi gereken yeni JavaScript kitaplıklarının, çoklu dolguların ve üçüncü taraf kodlarının eklenmesiyle bu özellikle zorlaşıyor.

Büyük JavaScript paketlerine dayanan istemci tarafı oluşturma özelliğini kullanan deneyimler, sayfa yükleme sırasında TBT ve INP'yi azaltmak için agresif kod bölmeyi değerlendirmeli ve JavaScript'i geç yüklediğinizden emin olmalıdır. "Yalnızca ihtiyaç duyduğunuzda, ihtiyacınız olduğunda sunun". Etkileşimin az olduğu veya hiç olmadığı deneyimler için sunucu tarafı oluşturma, bu sorunlara daha ölçeklenebilir bir çözüm olabilir.

Tek sayfalık uygulamalar oluşturan kullanıcılar için, çoğu sayfa tarafından paylaşılan kullanıcı arayüzünün temel bölümlerini tanımlamak, uygulama kabuğu önbelleğe alma tekniğini uygulayabileceğiniz anlamına gelir. Uygulama kabuğu HTML'si ve bağımlılıkları CacheStorage üzerinden çok hızlı bir şekilde yüklenebildiği için bu, hizmet çalışanları da dahil olmak üzere tekrarlanan ziyaretlerde algılanan performansı önemli ölçüde iyileştirebilir.

Yeniden kullanılabilirleştirme yoluyla sunucu tarafı oluşturma ile istemci tarafı oluşturmayı birleştirme

Bu yaklaşım, her ikisini de yaparak istemci taraflı oluşturma ile sunucu tarafı oluşturma arasındaki dengeleri yumuşatmaya çalışır. Tam sayfa yükleme veya yeniden yükleme gibi gezinme istekleri, uygulamayı HTML'ye dönüştüren bir sunucu tarafından işlenir, ardından, oluşturma için kullanılan JavaScript ve veriler oluşturulan dokümana yerleştirilir. Dikkatli bir şekilde uygulandığında bu işlem, sunucu tarafı oluşturmada olduğu gibi hızlı bir FCP sağlar, ardından (yeniden)hidrasyon adı verilen bir teknik kullanarak istemcide tekrar oluşturarak "alakalı" olur. Bu etkili bir çözüm olsa da önemli performans dezavantajlarına yol açabilir.

Yeniden kullanılabilir şekilde sunucu tarafı oluşturmanın birincil dezavantajı, FCP'yi iyileştirse bile TBT ve INP üzerinde önemli bir olumsuz etkiye sahip olabilmesidir. Sunucu tarafında oluşturulan sayfalar, yanıltıcı bir şekilde yüklenmiş ve etkileşimli olarak görünebilir, ancak bileşenlerin istemci tarafı komut dosyaları yürütülene ve etkinlik işleyiciler eklenene kadar girişlere yanıt veremez. Bu işlem mobil cihazlarda saniyeler, hatta dakikalar içinde sürebilir.

Muhtemelen bu durumu siz de yaşamışsınızdır. Bir sayfa yüklenmiş gibi göründükten bir süre sonra, tıklamak veya dokunmak hiçbir şey yapmaz. Kullanıcı sayfayla etkileşime geçmeye çalışırken neden hiçbir şey olmadığını merak ettiği için bu durum kısa süre içinde can sıkıcı hale gelir.

Sulama sorunu: İki ödeyerek bir uygulama

Yeniden kullanılabilirliğe ilişkin sorunlar genellikle JavaScript'ten kaynaklanan gecikmeli etkileşimden daha kötü olabilir. İstemci tarafı JavaScript'in, HTML'sini oluşturmak üzere kullandığı tüm verileri yeniden istemek zorunda kalmadan sunucunun kaldığı yerden doğru bir şekilde "alma" yapabilmesi için mevcut sunucu tarafı oluşturma çözümleri, genellikle kullanıcı arayüzünün veri bağımlılıklarından gelen yanıtı komut dosyası etiketleri olarak dokümana seriler. Ortaya çıkan HTML belgesi yüksek düzeyde yineleme içeriyor:

Serileştirilmiş kullanıcı arayüzü, satır içi veriler ve Bundle.js komut dosyası içeren HTML dokümanı

Gördüğünüz gibi, sunucu bir gezinme isteğine yanıt olarak uygulamanın kullanıcı arayüzünün açıklamasını döndürür, ancak aynı zamanda söz konusu kullanıcı arayüzünü oluşturmak için kullanılan kaynak verileri ve daha sonra, istemcide başlatılan kullanıcı arayüzü uygulamasının tam bir kopyasını da döndürür. Bu kullanıcı arayüzü, ancak bundle.js uygulamasının yüklenmesi ve yürütmesi bittikten sonra etkileşimli hale gelir.

Sunucu tarafı oluşturma ve yeniden kullanılabilirlik özellikleri kullanılarak gerçek web sitelerinden toplanan performans metrikleri, bu özelliğin kullanılmaması gerektiğini göstermektedir. Sonuç olarak, bunun nedeni kullanıcı deneyiminden kaynaklanıyor: Kullanıcıları, sayfa hazır görünse de bile etkileşimin olmadığı "ürkütücü vadide" bırakmak son derece kolaydır.

TTI&#39;yı olumsuz etkileyen istemci oluşturmayı gösteren şema.

Yine de, yeniden kullanılabilirleştirme yoluyla sunucu tarafında oluşturmanın umut ışığı var. Kısa vadede, yüksek oranda önbelleğe alınabilir içerikler için yalnızca sunucu tarafı oluşturmanın kullanılması TTFB'yi azaltarak önceden işlemeye benzer sonuçlar sağlayabilir. Artımlı, kademeli veya kısmen su sağlamak, bu tekniği gelecekte daha uygulanabilir hale getirmenin anahtarı olabilir.

Akış sunucusu tarafı oluşturma ve progresif rehidrasyon

Sunucu tarafı oluşturmada son birkaç yılda çeşitli geliştirmeler yapıldı.

Akış sunucu tarafı oluşturma, HTML'yi alındıkları anda tarayıcının kademeli olarak oluşturabileceği parçalar halinde göndermenize olanak tanır. İşaretleme kullanıcılara daha hızlı ulaştığından bu, hızlı bir FCP ile sonuçlanabilir. React'te, akışların [renderToPipeableStream()] içinde eşzamansız olması (eşzamanlı renderToString() ile karşılaştırıldığında) karşı basıncın iyi yönetildiği anlamına gelir.

Progresif rehidrasyon da dikkate alınması gereken bir nokta ve React'in sona erdirdiği bir gelişme. Bu yaklaşımda, uygulamanın tamamını bir defada başlatmaya yönelik geçerli yaygın yaklaşım yerine, sunucu tarafından oluşturulan bir uygulamanın her bir parçası zaman içinde "açılır". Sayfanın düşük öncelikli bölümlerinin istemci tarafında yeni sürüme geçirilmesi ana iş parçacığının engellenmesini önleyecek şekilde ertelenebileceği ve böylece kullanıcı etkileşimlerinin kullanıcı bunları başlattıktan hemen sonra gerçekleşmesine olanak tanıdığından, bu, sayfaları etkileşimli hale getirmek için gereken JavaScript miktarının azaltılmasına yardımcı olabilir.

Progresif yeniden kullanılabilirlik, sunucu tarafından oluşturulan bir DOM ağacının yok edilip hemen yeniden derlendiği, en yaygın sunucu tarafı oluşturma yeniden kullanılabilirlik risklerinden birini önlemenize yardımcı olabilir. Bunun nedeni çoğu zaman başlangıçtaki eş zamanlı istemci tarafı oluşturma işleminin tam olarak hazır olmayan (belki bir Promise çözümünün hazırlanmasını bekleyen veriler) gerektirmesidir.

Kısmi su kaybı

Kısmi rehidrasyonun uygulanması zor görülmüştür. Bu yaklaşım, progresif yeniden sulama fikrinin bir uzantısıdır. Burada, kademeli olarak yeniden suyun toplanacağı parçaların (bileşenler/görünümler/ağaçlar) analiz edilir ve etkileşimi az olan veya hiç tepkisiz olan parçaların tespit edilir. Çoğunlukla statik olan bu parçaların her biri için karşılık gelen JavaScript kodu, durağan referanslara ve dekoratif işlevlere dönüştürülüp istemci taraflı ayak izinin neredeyse sıfıra indirilmesini sağlıyor.

Kısmi sıvı alma yaklaşımının kendine has sorunları ve uzlaşmaları vardır. Önbelleğe alma açısından bazı ilginç zorluklar vardır ve istemci tarafında gezinme, uygulamanın durağan kısımları için sunucu tarafından oluşturulan HTML'nin tam sayfa yüklenmeden kullanılabilir olacağını varsayamayacağımız anlamına gelir.

Trisomorfik oluşturma

Service Worker'ları tercih ediyorsanız "trisomorfik" oluşturma da ilginizi çekebilir. Bu, ilk/JS olmayan gezinmeler için sunucu tarafında akış oluşturmayı kullanabileceğiniz ve ardından hizmet çalışanınızın yüklendikten sonra gezinmeler için HTML oluşturmayı üstleneceği bir tekniktir. Böylece, önbelleğe alınan bileşenleri ve şablonları güncel tutabilirsiniz. Ayrıca, aynı oturumda yeni görünümler oluşturmak için SPA stilinde gezinme yapabilirsiniz. Bu yaklaşım; sunucu, istemci sayfası ve hizmet çalışanı arasında aynı şablon ve yönlendirme kodunu paylaşabildiğinizde en iyi sonucu verir.

Sunucuyla iletişim kuran bir tarayıcı ve Service Worker&#39;ı gösteren Trisomorfik oluşturma şeması.

SEO ile ilgili dikkat edilmesi gereken noktalar

Ekipler genellikle web'de oluşturma stratejisi belirlerken SEO'nun etkisini hesaba katar. Sunucu tarafı oluşturma genellikle tarayıcıların kolayca yorumlayabileceği "eksiksiz" bir deneyim sunmak için seçilir. Tarayıcılar JavaScript'i anlayabilir, ancak çoğu zaman bunların nasıl oluşturulduğu konusunda dikkat edilmesi gereken kısıtlamalar vardır. İstemci taraflı oluşturma çalışabilir ancak genellikle ek testler ve destek olmadan olmaz. Daha yakın zamanlarda, mimariniz büyük ölçüde istemci taraflı JavaScript'e dayanıyorsa dinamik oluşturma da değerlendirilmeye değer bir seçenek haline gelmiştir.

Mobil uyumluluk testi aracının, seçtiğiniz yaklaşımın beklediğiniz sonuçları verip vermediğini test etmek açısından şüpheye düşerseniz son derece yararlıdır. Bu rapor, herhangi bir sayfanın Google'ın tarayıcısına nasıl göründüğü, serileştirilmiş HTML içeriğinin bulunduğu (JavaScript yürütüldükten sonra) ve oluşturma sırasında karşılaşılan hataların görsel bir önizlemesini gösterir.

Mobil Uyumluluk Testi kullanıcı arayüzünün ekran görüntüsü.

Özet

Oluşturma yaklaşımına karar verirken performans sorunlarını ölçün ve anlayın. Statik oluşturmanın mı yoksa sunucu tarafı oluşturmanın mı size en iyi şekilde yol gösterebileceğini düşünün. Etkileşimli bir deneyim elde etmek için çoğunlukla HTML'yi minimal JavaScript ile göndermeniz son derece uygundur. Sunucu-istemci spektrumunu gösteren kullanışlı bir infografike aşağıda yer verilmiştir:

Bu makalede açıklanan seçenek yelpazesini gösteren infografik.

Kredi

İncelemeleri ve ilham verdikleri için herkese teşekkür ederiz:

Jeffrey Posnick, Houssein Djirdeh, Shubhie Panicker, Chris Harrelson ve Sebastian Markbåge