Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtma

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtma

Habr'ın içeriden nasıl yapılandırıldığı, iş akışının nasıl yapılandırıldığı, iletişimin nasıl yapılandırıldığı, hangi standartların kullanıldığı ve burada kodun genel olarak nasıl yazıldığı her zaman ilgimi çekmiştir. Neyse ki böyle bir fırsat yakaladım çünkü yakın zamanda Habra ekibinin bir parçası oldum. Mobil sürümün küçük bir yeniden düzenlenmesi örneğini kullanarak şu soruyu yanıtlamaya çalışacağım: burada ön planda çalışmak nasıl bir şey? Programda: Habr'daki kişisel deneyime ilişkin notlardan soslu Node, Vue, Vuex ve SSR.

Geliştirme ekibi hakkında bilmeniz gereken ilk şey, sayımızın az olduğudur. Yeterli değil - bunlar üç ön, iki arka ve tüm Habr - Baxley'in teknik lideri. Elbette bir testçi, bir tasarımcı, üç Vadim, bir mucize süpürge, bir pazarlama uzmanı ve diğer Bumburum'lar da var. Ancak Habr'ın kaynaklarına doğrudan katkıda bulunan yalnızca altı kişi var. Bu oldukça nadirdir - dışarıdan dev bir işletme gibi görünen multimilyon dolarlık bir izleyici kitlesine sahip bir proje, gerçekte mümkün olan en düz organizasyon yapısına sahip rahat bir başlangıç ​​​​gibi görünüyor.

Diğer birçok BT şirketi gibi Habr da Çevik fikirleri, CI uygulamalarını savunuyor ve hepsi bu. Ama bana göre Habr bir ürün olarak sürekli olmaktan ziyade dalgalar halinde gelişiyor. Böylece, art arda birkaç sprint için, bir şeyi özenle kodlar, tasarlar ve yeniden tasarlarız, bir şeyi kırıp onarırız, biletleri çözer ve yenilerini yaratırız, tırmığa basarız ve sonunda özelliği serbest bırakmak için kendimizi ayaklarımızdan vururuz. üretme. Ve sonra belli bir durgunluk gelir, bir yeniden gelişme dönemi gelir, "önemli-acil değil" çeyreğinde olanı yapma zamanı gelir.

Aşağıda tartışılacak olan tam olarak bu "sezon dışı" sprinttir. Bu kez Habr'ın mobil versiyonunun yeniden düzenlenmesi de dahil. Genel olarak şirketin bu konuda büyük umutları var ve gelecekte Habr'ın enkarnasyonlarının tüm hayvanat bahçesinin yerini alması ve evrensel bir platformlar arası çözüm haline gelmesi gerekiyor. Bir gün uyarlanabilir düzen, PWA, çevrimdışı mod, kullanıcı özelleştirme ve daha birçok ilginç şey olacak.

Görevi belirleyelim

Bir keresinde, sıradan bir stand-up'ta, ön cepheden biri, mobil versiyonun yorum bileşeninin mimarisindeki sorunlardan bahsetmişti. Bu düşünceyle grup psikoterapisi formatında bir mikro toplantı düzenledik. Herkes sırayla nerenin acıdığını söyledi, her şeyi kağıda kaydettiler, sempati duydular, anladılar ama kimse alkışlamadı. Sonuçta 20 sorundan oluşan bir liste ortaya çıktı ve bu liste, mobil Habr'ın başarıya giden yolunun hala uzun ve dikenli olduğunu açıkça ortaya koydu.

Öncelikle kaynak kullanımının verimliliği ve pürüzsüz arayüz denen şeyle ilgileniyordum. Her gün, ev-iş-ev yolunda, eski telefonumun çaresizce haber akışında 20 haber başlığı göstermeye çalıştığını görüyordum. Şunun gibi bir şeye benziyordu:

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtmaYeniden düzenlemeden önce Mobil Habr arayüzü

Burada neler oluyor? Kısacası sunucu, kullanıcının oturum açıp açmamasına bakılmaksızın HTML sayfasını herkese aynı şekilde sundu. Daha sonra istemci JS yüklenir ve gerekli verileri tekrar ister, ancak yetkilendirme için ayarlanır. Yani aslında aynı işi iki kez yaptık. Arayüz titredi ve kullanıcı fazladan yüz kilobayt indirdi. Ayrıntılı olarak her şey daha da ürkütücü görünüyordu.

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtmaEski SSR-CSR şeması. Yetkilendirme yalnızca C3 ve C4 aşamalarında, Node JS'nin HTML oluşturmakla meşgul olmadığı ve API'ye istekleri proxy olarak gerçekleştirebildiği durumlarda mümkündür.

O zamanın mimarisini Habr kullanıcılarından biri çok doğru bir şekilde tanımlamıştı:

Mobil versiyonu berbat. Ben olduğu gibi söylüyorum. SSR ve CSR'nin korkunç bir kombinasyonu.

Ne kadar üzücü olursa olsun bunu kabul etmek zorundaydık.

Seçenekleri değerlendirdim, Jira'da "şimdi kötü, doğru yap" düzeyinde bir açıklama içeren bir bildirim oluşturdum ve görevi geniş vuruşlara ayırdım:

  • verileri yeniden kullanın,
  • yeniden çizim sayısını en aza indirin,
  • yinelenen istekleri ortadan kaldırın,
  • Yükleme işlemini daha belirgin hale getirin.

Verileri yeniden kullanalım

Teorik olarak, sunucu tarafı oluşturma iki sorunu çözmek için tasarlanmıştır: arama motoru sınırlamalarından etkilenmemek. SPA indeksleme ve metriği iyileştirin FMP (kaçınılmaz olarak kötüleşen TTI). Klasik bir senaryoda nihayet 2013 yılında Airbnb'de formüle edildi yıl (hala Backbone.js'de), SSR, Node ortamında çalışan aynı izomorfik JS uygulamasıdır. Sunucu, oluşturulan düzeni isteğe yanıt olarak gönderir. Daha sonra istemci tarafında yeniden doldurma gerçekleşir ve ardından her şey sayfa yeniden yüklenmeden çalışır. Metin içeriğine sahip diğer birçok kaynak gibi Habr için de sunucu oluşturma, arama motorlarıyla dostane ilişkiler kurmada kritik bir unsurdur.

Teknolojinin ortaya çıkışından bu yana altı yıldan fazla zaman geçmiş olmasına ve bu süre zarfında ön uç dünyasında köprünün altından gerçekten çok su akmış olmasına rağmen, birçok geliştirici için bu fikir hala gizlilik içindedir. Kenara çekilmedik ve küçük bir ayrıntıyı atlayarak SSR destekli bir Vue uygulamasını üretime sunduk: istemciye ilk durumu göndermedik.

Neden? Bu sorunun kesin bir cevabı yok. Ya sunucudan gelen yanıtın boyutunu artırmak istemediler ya da bir dizi başka mimari sorun nedeniyle ya da başarılı olamadılar. Öyle ya da böyle, durumu atmak ve sunucunun yaptığı her şeyi yeniden kullanmak oldukça uygun ve faydalı görünüyor. Görev aslında önemsizdir - durum basitçe enjekte edilir yürütme bağlamına eklenir ve Vue bunu otomatik olarak oluşturulan düzene global bir değişken olarak ekler: window.__INITIAL_STATE__.

Ortaya çıkan sorunlardan biri döngüsel yapıların JSON'a dönüştürülememesidir (dairesel referans); bu tür yapıların düz benzerleriyle değiştirilmesiyle çözüldü.

Ayrıca UGC içeriğiyle uğraşırken HTML'nin bozulmaması için verilerin HTML öğelerine dönüştürülmesi gerektiğini unutmamalısınız. Bu amaçlar için kullanıyoruz he.

Yeniden çizimleri en aza indirme

Yukarıdaki şemada görebileceğiniz gibi, bizim durumumuzda, bir Node JS örneği iki işlevi yerine getirir: SSR ve API'de kullanıcı yetkilendirmesinin gerçekleştiği "proxy". Bu durum, düğüm tek iş parçacıklı olduğundan ve SSR işlevi senkronize olduğundan, JS kodu sunucuda çalışırken yetkilendirmeyi imkansız hale getirir. Yani, çağrı yığını bir şeyle meşgulken sunucu kendisine istek gönderemez. Durumu güncellediğimiz ortaya çıktı, ancak istemcideki verilerin kullanıcı oturumu dikkate alınarak güncellenmesi gerektiğinden arayüz seğirmeyi durdurmadı. Uygulamamıza, kullanıcının oturum açma bilgilerini dikkate alarak doğru verileri başlangıç ​​durumuna getirmeyi öğretmemiz gerekiyordu.

Sorunun yalnızca iki çözümü vardı:

  • yetkilendirme verilerini sunucular arası isteklere eklemek;
  • Node JS katmanlarını iki ayrı örneğe bölün.

İlk çözüm, sunucuda global değişkenlerin kullanılmasını gerektiriyordu ve ikincisi, görevin tamamlanması için son tarihi en az bir ay uzattı.

Nasıl seçim yapılır? Habr çoğu zaman en az dirençli yolda ilerliyor. Gayri resmi olarak fikirden prototipe olan döngüyü en aza indirmeye yönelik genel bir istek vardır. Ürüne yönelik tutum modeli, bir şekilde booking.com'un varsayımlarını anımsatıyor; tek fark, Habr'ın kullanıcı geri bildirimlerini çok daha ciddiye alması ve bir geliştirici olarak bu tür kararları vermeniz konusunda size güvenmesidir.

Bu mantığı ve sorunu hızlı bir şekilde çözme arzumu takip ederek global değişkenleri seçtim. Ve çoğu zaman olduğu gibi, er ya da geç bunların bedelini ödemek zorunda kalırsınız. Neredeyse anında ödedik: hafta sonu çalıştık, sonuçları netleştirdik, yazdık postmortem ve sunucuyu iki parçaya bölmeye başladı. Hata çok aptalcaydı ve onu içeren hatanın yeniden üretilmesi kolay değildi. Ve evet, bunun için utanç verici, ama öyle ya da böyle, tökezleyerek ve inleyerek, küresel değişkenlere sahip PoC'm yine de üretime girdi ve yeni bir "iki düğümlü" mimariye geçişi beklerken oldukça başarılı bir şekilde çalışıyor. Bu önemli bir adımdı çünkü resmi olarak hedefe ulaşıldı; SSR tamamen kullanıma hazır bir sayfa sunmayı öğrendi ve kullanıcı arayüzü çok daha sakin hale geldi.

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtmaYeniden düzenlemenin ilk aşamasından sonra Mobil Habr arayüzü

Sonuçta mobil versiyonun SSR-CSR mimarisi şu tabloyu ortaya çıkarıyor:

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtma“İki düğümlü” SSR-CSR devresi. Node JS API her zaman eşzamansız G/Ç için hazırdır ve SSR işlevi ayrı bir örnekte bulunduğundan SSR işlevi tarafından engellenmez. Sorgu zinciri #3 gerekli değildir.

Yinelenen isteklerin ortadan kaldırılması

Manipülasyonlar gerçekleştirildikten sonra, sayfanın ilk gösterimi artık epilepsiyi tetiklemiyordu. Ancak Habr'ın SPA modunda daha fazla kullanılması hala kafa karışıklığına neden oldu.

Kullanıcı akışının temeli form geçişleri olduğundan makale listesi → makale → yorumlar ve tam tersi, ilk etapta bu zincirin kaynak tüketimini optimize etmek önemliydi.

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtmaGönderi akışına geri dönmek yeni bir veri isteğine neden olur

Derin kazmaya gerek yoktu. Yukarıdaki ekran görüntüsünde uygulamanın geriye doğru kaydırdığınızda makale listesini yeniden istediğini, istek sırasında makaleleri göremediğimizi, yani önceki verilerin bir yerlerde kaybolduğunu görebilirsiniz. Görünüşe göre makale listesi bileşeni yerel bir durum kullanıyor ve yok edildiğinde onu kaybediyor. Aslında uygulama küresel bir durum kullanıyordu, ancak Vuex mimarisi doğrudan inşa edildi: modüller sayfalara, onlar da rotalara bağlı. Dahası, tüm modüller "tek kullanımlıktır" - sayfaya yapılan sonraki her ziyaret, modülün tamamını yeniden yazmıştır:

ArticlesList: [
  { Article1 },
  ...
],
PageArticle: { ArticleFull1 },

Toplamda bir modülümüz vardı Makale Listesitüründe nesneler içeren makale ve modül SayfaMakale, nesnenin genişletilmiş bir versiyonuydu makale, biraz MakaleTam. Genel olarak, bu uygulama kendi içinde korkunç bir şey taşımıyor - çok basit, hatta saf bile denilebilir, ancak son derece anlaşılır. Rotayı her değiştirdiğinizde modülü sıfırlarsanız, onunla yaşayabilirsiniz. Ancak, örneğin makale akışları arasında geçiş yapmak /feed → /tümü, elimizde yalnızca bir tane olduğundan, kişisel beslemeyle ilgili her şeyi çöpe atması garanti edilir Makale Listesiiçine yeni veriler koymanız gereken. Bu da bizi yine isteklerin çoğalmasına yol açıyor.

Konuyla ilgili bulabildiğim her şeyi toplayarak yeni bir devlet yapısı oluşturdum ve bunu meslektaşlarıma sundum. Tartışmalar uzun sürdü ama sonunda lehine olan argümanlar şüphelere ağır bastı ve uygulamaya başladım.

Çözümün mantığı en iyi iki adımda ortaya çıkar. Öncelikle Vuex modülünü sayfalardan ayırmaya ve doğrudan rotalara bağlamaya çalışıyoruz. Evet, mağazada biraz daha fazla veri olacak, alıcılar biraz daha karmaşık hale gelecek, ancak makaleleri iki kez yüklemeyeceğiz. Mobil versiyon için bu belki de en güçlü argümandır. Bunun gibi bir şeye benzeyecek:

ArticlesList: {
  ROUTE_FEED: [ 
    { Article1 },
    ...
  ],
  ROUTE_ALL: [ 
    { Article2 },
    ...
  ],
}

Peki ya makale listeleri birden fazla rota arasında çakışabilirse ve nesne verilerini yeniden kullanmak istersek ne olur? makale gönderi sayfasını oluşturmak ve dönüştürmek için MakaleTam? Bu durumda şöyle bir yapıyı kullanmak daha mantıklı olacaktır:

ArticlesIds: {
  ROUTE_FEED: [ '1', ... ],
  ROUTE_ALL: [ '1', '2', ... ],
},
ArticlesList: {
  '1': { Article1 }, 
  '2': { Article2 },
  ...
}

Makale Listesi burası sadece bir tür makale deposu. Kullanıcı oturumu sırasında indirilen tüm makaleler. Onlara son derece dikkatli davranıyoruz, çünkü bu metroda istasyonlar arasında bir yerde ağrı yoluyla indirilmiş olabilecek bir trafik ve kullanıcıyı zaten sahip olduğu verileri yüklemeye zorlayarak bir daha bu acıyı yaşatmak istemiyoruz. İndirildi. Bir obje MakalelerKimlikler basitçe nesnelere yönelik bir kimlik dizisidir (sanki "bağlantılar" gibi) makale. Bu yapı, rotalarda ortak olan verilerin kopyalanmasını ve nesnenin yeniden kullanılmasını önlemenizi sağlar makale genişletilmiş verileri birleştirerek bir gönderi sayfası oluştururken.

Makale listesinin çıktısı da daha şeffaf hale geldi: yineleyici bileşen, makale kimliklerini içeren dizi boyunca yinelenir ve kimliği bir destek olarak ileterek makale teaser bileşenini çizer ve alt bileşen de sırayla gerekli verileri alır. Makale Listesi. Yayın sayfasına gittiğinizde, mevcut tarihi şuradan alırız: Makale Listesieksik verileri elde etmek için bir talepte bulunuruz ve onu mevcut nesneye ekleriz.

Bu yaklaşım neden daha iyi? Yukarıda yazdığım gibi bu yaklaşım, indirilen verilere göre daha yumuşaktır ve onu yeniden kullanmanıza olanak tanır. Ancak bunun yanı sıra, böyle bir mimariye mükemmel uyum sağlayan bazı yeni olanakların da önünü açıyor. Örneğin, makaleleri göründükleri anda yayına oylama ve yükleme. En son gönderileri bir “depolama”ya koyabiliriz Makale Listesi, yeni kimliklerin ayrı bir listesini şuraya kaydedin: MakalelerKimlikler ve kullanıcıyı bu konuda bilgilendirin. “Yeni yayınları göster” butonuna tıkladığımızda, mevcut makale listesi dizisinin başına yeni kimlikleri ekleyeceğiz ve her şey neredeyse sihirli bir şekilde çalışacaktır.

İndirmeyi daha keyifli hale getirme

Yeniden düzenleme pastasının kreması, yavaş bir İnternet üzerinden içerik indirme sürecini biraz daha az iğrenç hale getiren iskelet kavramıdır. Bu konuda hiçbir tartışma olmadı; fikirden prototipe giden yol tam anlamıyla iki saat sürdü. Tasarım pratik olarak kendini çizdi ve bileşenlerimize veri beklerken basit, zar zor titreyen div blokları oluşturmayı öğrettik. Sübjektif olarak, bu yükleme yaklaşımı aslında kullanıcının vücudundaki stres hormonu miktarını azaltır. İskelet şöyle görünüyor:

Habr ön uç geliştirici günlükleri: yeniden düzenleme ve yansıtma
Habrayükleniyor

yansıtan

Altı aydır Habré'de çalışıyorum ve arkadaşlarım hâlâ soruyor: Peki orayı nasıl buldun? Tamam, rahat - evet. Ancak bu çalışmayı diğerlerinden farklı kılan bir şey var. Ürünlerine tamamen kayıtsız kalan, kullanıcılarının kim olduğunu bilmeyen ve anlamayan ekiplerde çalıştım. Ama burada her şey farklı. Burada yaptığınız şeyden kendinizi sorumlu hissedersiniz. Bir özelliğin geliştirilmesi sürecinde kısmen onun sahibi olursunuz, işlevselliğinizle ilgili tüm ürün toplantılarına katılır, önerilerde bulunur ve kararları kendiniz verirsiniz. Her gün kullandığınız bir ürünü kendi başınıza yapmak çok güzel, ancak bu konuda muhtemelen sizden daha iyi olan insanlar için kod yazmak inanılmaz bir duygu (alaycılık değil).

Tüm bu değişikliklerin yayınlanmasının ardından olumlu geri dönüşler aldık ve çok ama çok güzeldi. İlham verici. Teşekkür ederim! Daha fazla yaz.

Global değişkenlerden sonra mimariyi değiştirmeye ve proxy katmanını ayrı bir örneğe ayırmaya karar verdiğimizi hatırlatayım. “İki düğümlü” mimari halihazırda halka açık beta testi biçiminde piyasaya sürüldü. Artık herkes bu uygulamaya geçebilir ve mobil Habr'ı daha iyi hale getirmemize yardımcı olabilir. Hepsi bugün için. Tüm sorularınızı yorumlarda yanıtlamaktan mutluluk duyacağım.

Kaynak: habr.com

Yorum ekle