Stourl.com’u Nasıl Geliştirdim?

Mehmet Ali Ayvaz
11 min readJul 6, 2021

--

Not: Bu makalede, henüz tecrübemin çok olmadığı zamanlarda geliştirdiğim proje olan Stourl.com’un ilk versiyonu hakkında bilgiler verdim. Burada bahsettiğim birçok yöntem o zamanın şartlarında işimi en kolay şekilde çözebilecek yöntemlerdi, elbette birçok farklı yol olabilir.

Merhabalar, bu yazımda Stourl.com‘u nasıl geliştirdiğimi, geliştirirken neler kullandığım hakkında bilgi vereceğim.

Öncelikle Stourl ne işe yarıyor, kısaca bundan bahsedeyim. Stourl ile linklerinizi kaydedebilir, linkleri bir araya getirerek liste oluşturabilir, insanlarla kaydettiğiniz linkleri ve oluşturduğunuz listeleri paylaşabilirsiniz.

Stourl fikri bu şekilde ortaya çıkmadı. Yaklaşık beş sene önce hayalimde çeşitli özellikleri olan bir link kısaltma aracı kurmak vardı. Bu araç ile linkleri şifreleyebilme, kısaltılan linke özel url oluşturabilme, kısaltılan linkleri kaydetme gibi birçok işlem yapılabilecekti.

Projenin ismi o zamanlar “Storage Url” in kısaltması olarak “Storl” düşünmüştüm. Ne yazık ki domain boşta olmadığı için ismi “Stourl” olarak güncelledim. Hemen stourl.com domainini satın aldım. Maalesef o zamanki bilgimin yetersizliğinden projeyi erteledim.

2018’de bilgisayar mühendisliğini kazanıp İstanbul’a yerleştim. Okul haricinde kendimi geliştirmek istiyordum. Temel yazılım bilgim vardı ve bir alana yönelip o alandan ilerlemek istiyordum. Öncelikle mobil uygulama geliştirmek istesem de daha sonra web alanına yöneldim. Kendim için doğru alanı bulmuştum, artık kendimi web alanında geliştirebilirdim.

Youtube üzerinden çeşitli kanallardan css dersleri izleyerek anlamaya gayret ediyordum ancak tam anlamıyla mantığımın oturması Adem İlter‘in booking.com tasarımını kodladığı serisinde oldu. 5 videoluk bu serisi ile gulp, scss, flexbox gibi kavramları öğrendim. Scss yazımı konusunda bana çok katkısı oldu. Ayrıca kanalındaki eğitim serilerinin bana çok katkısı oldu. Sayesinde Figma ile tasarım yapmayı da öğrendim.

Daha sonra javascript üzerine kendimi geliştirmem lazımdı. Mustafa Murat Coşkun ve Sadık Turan’ın javascript eğitimleri ile birçok konuyu öğrendim. Artık bir frameworke yönelme zamanım gelmişti.

Vue.js öğrenebileceğimi düşündüm fakat yeterli türkçe kaynak yoktu. Fatih Acet’in videoları ile Vue.js’e giriş yaptım. Vue.js’e dair kafamda bir şeyler oturmaya başlamıştı. Ve Vue.js’in syntax’ı oldukça hoşuma gitmişti.

Daha sonra Gökhan Kandemir‘in Vue.js udemy eğitimini satın alarak örnek minik projeler yapmaya başladım. Artık gün geçtikçe daha fazla konunun mantığı kafamda oturuyordu.

Vue.js’de belli bir seviyeye gelince Stourl’u kodlayabileceğimi düşündüm. Oldukça büyük ve karışık bir projeydi. En azından bazı özelliklerini devre dışı bırakarak kodlayabileceğimi düşündüm.

O zamanlar koronavirüs çıktığı için üniversiteler uzaktan eğitime geçmişti. Evde durmam vakit açısından bana avantaj sağlamıştı.

Tasarımın Yapılması ve Kodlanması

Öncelikle projenin tasarımını figma ile yapmaya başladım. Tasarım esnasında projenin bazı özelliklerini değiştirmiştim. Yaz zamanı tasarımı scss ile kodlamaya başladım. Önce tasarımı kodlayıp sonra Vue.js altyapısına geçirmeyi düşündüm.

Scss kullanarak tasarımı koda döktüm. Ancak Vue.js altyapısına geçirirken bunun mantıklı olmadığını anladım. Direk Vue.js ile yeni bir proje oluşturup component bazlı kodlamanın daha doğru olduğunu gördüm.

İlk Ayarlamalar

Tasarımı Vue.js altyapısına geçirdikten sonra Vue-Router, Vuex ve Axios kütüphanelerini kurdum. İlk olarak Vue-Router ile sayfa yönlendirmelerini ayarladım.

Store’u state, actions, mutations ve getter olarak sayfalara ayırdım. Böylece daha erişilebilir bir store yapısı kurdum. Proje ilerledikçe kodlarımı ilgili bölümlere yazacaktım. Ancak proje ilerledikçe modül yapısını kullanmam gerektiğinin farkına vardım çünkü dosyaları böldüğüm halde dosyalardaki kodlar oldukça fazlaydı. Stourl’un yeni sürümünde modül yapısına geçiş yapacağım, böylece çok daha kullanılabilir ve anlaşılabilir bir store yapısı olacaktır.

Stourl.com’un giriş yapmadan açılan ana sayfası için “Jquery Parallaxie” kütüphanesini kullandım. Bu kütüphane oldukça şık bir efekt veriyordu.

Veritabanı Seçimi

Veritabanı olarak Google Firebase-Firestore kullanmaya karar verdim. Daha önceki projelerimde de Firebase kullandığım için Firestore’u tercih ettim.

Firestore’un sunduğu özellikler işimi hemen hemen karşılayacaktı. Sadece bir-iki yerde çözüme kavuşturamadığım konu oldu, onları da geçici yöntemlerle çözdüm. Yazının devamında çözüm yöntemlerimden bahsettim.

Firestore oldukça güzel bir servis fakat ücretsiz limitleri bir yere kadar. Günlük 50 bin okuma, 20 bin yazma ve 20 bin silme işlemini ücretsiz yapabiliyorsunuz. Yazma ve silme kotaları fazlasıyla yetiyor ancak okuma kotası yetmeyecekti.

Firestore 100 bin okuma başına 0.06 dolar ücret alıyor. Ortalama olarak günlük 1 milyon okumaya ulaşınca ayda 18 dolar gibi bir ücret karşıma çıkacaktır. Şuan bunlar sadece tahmin… İlerde ne kadar kullanım olduğunu göreceğiz.

Auth İşlemleri

Auth işlemleri için Firebase Authentication kullandım. Firebase Auth, ücretsiz olarak günlük 10 bin kullanıcı limiti sunuyordu. Bu sınır bana rahatlıkla yeterdi.

Şuan için sadece email ile üye olma seçeneğini aktif hale getirdim ve başka bir üyelik yöntemi de düşünmüyorum.

Firebase her üye olan kullanıcıya bir id atıyor. Bu id’yi birçok alanda kullanabilirdim. Kullanıcı üye olunca firebase auth kısmına sadece mail adresi kaydediliyor. Firebase kullanıcıların şifresini göstermiyor. Üye olan kullanıcının kullanıcı adı, hakkında yazısı, sosyal medya linkleri gibi birçok bilgi de veritabanında tutulacağı için şöyle bir yöntem düşündüm:

Kullanıcı üye olduğu an firebase auth üzerinden otomatik oluşturulan kullanıcı id’yi alıp firestore içinde ‘users’ tablosunda bu id ile bir doküman oluşturuyorum. Bu dokümanın içine, kullanıcı üye olurken form alanına girdiği adı kullanıcı adını, mailini ekliyorum.

Daha sonra kullanıcı ayarlar kısmından kendi hakkında yazısını, sosyal medya hesaplarının linklerini eklediğinde, bu bilgileri yine bu dokümanın içinde tutuyorum. Eğer kullanıcıya dair başka bilgilerin tutulması gerekirse yine bu dokümanı kullanabilirim.

Giriş yapmadan ve giriş yaptıktan sonra farklı ana sayfaların gösterilmesi için router ile basit bir kontrol yapısı oluşturdum. Kullanıcının oturumu açık olup olmadığını kontrol edip ilgili ana sayfa ekranda gösteriliyor.

Uyarı ve Bilgilendirme Kutuları

Stourl.com üzerindeki uyarılar ve bilgilendirmeler için vue-toast kütüphanesini kullandım. Bilgilendirme kutularını sayfanın sağ altında kısa bir süreliğine gösterecek şekilde ayarladım.

Link Kaydetme İşlemi

Gelelim dinamik kullanıcı işlemlerine. İlk olarak link kaydetme kısmıyla başladım. Kullanıcının kaydetmek istediği linki Stourl.com üzerinde link başlığı ile göstermemiz gerekiyordu. Linkin başlığını ve domainini elde edebileceğim bir api yardımıyla bu sorunu çözdüm.

Link kaydetme componentinde link girişi, açıklama kısmı ve en fazla üç etiket ekleyebileceği bir alan oluşturdum. Link açıklaması ve etiket kısmı isteğe bağlı doldurulabilen alanlar olarak ayarladım.

Kullanıcı linki ekleyip “Ekle” butonuna bastığı anda state içine link ekleniyor. Daha sonra api ile link başlığını ve domainini elde edip veritabanına ekleme işlemi yaptırıyorum. Link veritabanına kaydolduğu anda veritabanından çekiliyor, başlık ve domain güncellenip işlem tamamlanıyor.

Link Çekim İşlemi

İlk başta link çekim işleminde link içeriğiyle kullanıcı bilgisini ayrı tablolardan çekilecek diye düşünmüştüm. Ama Firestore’un resmi youtube kanalında yer alan videolarda bu yöntemin maliyetli bir işlem olacağını söylüyordu.

Videoda, kullanıcı bilgisini ve içeriği ayrı tablolardan çekmek yerine, her içeriğin içinde kullanıcı bilgisinin de yer alması gerektiğini söylüyordu. Bunu kendi sistemimizde düşünecek olursak, her linkin içine isim, kullanıcı adı ve kullanıcı profilinin resim linkini de kaydettirdim. Böylece linkler çekilirken tek bir tablo üzerinden çekim işlemi yapılıyordu. Böylece daha optimum bir çekim işlemi gerçekleştirdim.

Peki akıllara takılan bir soru var… Kullanıcı, ismini veya kullanıcı adını değiştirdiğinde sistem üzerine kaydettiği tüm linkler güncellenecek mi? Resmi firestore videosuna göre kullanıcı bilgisini değiştirdiğinde, her içeriğin içinden kullanıcı bilgisini değiştirmek, kullanıcı bilgisini ve içeriği farklı tablolardan çekmekten daha optimum bir durumdur. Ancak bu da bir maliyet doğuracağından kullanıcının ismini ve kullanıcı adını değiştirmeye izin vermedim.

Böylece bir link componentinin içinde değişken olan sadece profil resminin linki kaldı. Kullanıcı her profil resmini değiştirdiğinde, link componentinin içinden profil resminin linki değişecek mi?

Bunun için ilk olarak aklıma bir yol geldi; gravatar kullanmak. Gravatar sunduğu api üzerinden kullanıcının profil resmini kullanmayı sağlıyor. Üstelik kullanıcı üye olduğu maille istediği kadar profil resmini değişsin, her zaman profil resminin linki sabit kalıyor. Buradaki mantık şöyle işliyor: Gravatar kullanıcının üye olduğu maili md5 algoritması ile şifreliyor. Böylece kullanıcıya özel linki, şifrelediği md5 koduyla oluşturuyor. Böylece link hep sabit kalarak profil resmini değiştirmesine izin veriyor.

Bu mantığı kullanarak gravatar seçeneğinin yanında, gravatar hesabı olmayan kullanıcılar için sistem üzerine profil resmini yükleyebilmesi için bir kısım yaptım. Kullanıcı Stourl.com’a üye olduğu anda, mail adresini kullanıcı bilgileri arasına md5 olarak çevirip saklatıyorum. Böylece istediğim domain üzerinde o md5 kodu ile profil resmi depolamayı sağlatıyorum. Kullanıcı profil resmini istediği kadar değiştirebilir, sonuçta link hep aynı kalıyor. Bunu ister gravatar üzerinden, ister Stourl.com üzerinden ister de başka bir servis üzerinde barındırarak kullanabiliyoruz.

Bu mantığı kullanarak hostingin içinde barınacak şekilde avatar yükleme sistemi oluşturabilirdim. Halihazırda Firebase’in sunduğu “Storage” aracı ile profil resimlerini depolamayı uygun gördüm. Kullanıcı profil resmini yüklediği anda, fotoğrafın linki Firebase üzerine mail adresinin md5 karşılığı olarak kaydediliyor. Böylece link componentinin içine kullanıcının mail adresinin md5 karşılığını kaydetmem yeterli oluyordu.

Md5-converter kütüphanesi sayesinde her kullanıcı üye olduğu anda bilgilerinin arasına, mailinin md5 karşılığını kaydettiriyorum. Gerekli yerlerde bu md5 karşılığını kullanabiliyorum.

Linkin Eklendiği Tarihi Gösterme

Gelelim link üzerindeki tarih kısmına… Bunun için link veritabanına kaydedilirken otomatik olarak bir date objesi oluşturuyorum. “getTime()” fonksiyonu date objesi ile kullanıldığında 1970’ten o ana kadar geçen milisaniyeyi verir. Her linkin içine bu milisaniye bilgisini kaydediyorum. Linkler Firestore üzerinden çekilirken “Order By” özelliğini kullanarak linkleri milisaniyelerine göre büyükten küçüğe doğru sıralıyorum. Böylece linkleri tarihe göre sıralanmış bir şekilde çekebiliyorum, en yakın zamanda eklenen link en başta görünüyor.

Bu milisaniyeyi belli sayılara bölerek, bölüm ve kalan bilgisiyle o linkin eklendiği tarihin üzerinden geçen zamanı yıl, ay, gün, saat, dakika ve saniye olarak bulabiliyorum.

Çekilen linklerin üzerinde tarih gösterilirken, eğer aynı gün içerisindeyse sırasıyla sn, d, s olarak gösteriliyor. Eklenen linkin üzerinden bir gün geçmişse gün ve ay gösteriliyor. Eğer geçen yıl eklenmişse, tarihin yanına yıl da ekleniyor.

Bu gösterim şeklini filters kullanarak yaptım. Veritabanından çekilen linkteki milisaniye filters üzerinden geçerek bu işlemler uygulanıyor. Ve yukarıda bahsettiğim şekilde gösterim sağlanıyor.

Liste Oluşturma

Gelelim liste oluşturmaya… Ana sayfadaki iki buton aracılığıyla “link ekle” ve “liste oluştur” seçenekleri seçilebiliyor.

İlk başta liste ekleme componentini kodlarken önce kullanıcıdan listenin içerdiği linkleri alıp veritabanına kaydettiriyordum. Sonra liste içindeki her linkin başlığını güncellemesi için api üzerine istek yaptırıyordum. Böyle yapmak yerine kullanıcı listeye bir link eklediği anda api üzerine istek yapılıp linkin başlığını ve domainini ekran üzerinde göstertiyorum.

Linkler ve listeler veritabanında aynı tablo içerisinde tutuluyor. Link mi liste mi olduğunun bilgisi her birinin içerisinde bir boolean ifadesiyle yer alıyor. Böylece listeler, linklerden farklı olarak aşağı doğru açılabiliyor.

Takip Edilen Kişilere Ait Linklerin Çekimi

Ana sayfada, kullanıcının takip ettiği kişilere ait olan linklerin ve listelerin gösterilmesi gerekiyor. Kullanıcının takip ettiği kişiler veritabanında kendi bilgilerinin içindeki bir dizide tutuluyor. Ancak Firestore maximum on elemanlı bir dizi ile sorgulama yapmaya izin veriyor.

Bu sorunu da şöyle çözdüm: ana sayfa created olduğu anda store içerisinde yer alan takip edilen kişiler dizisinden random olarak çekilen 10 kişi ile yeni bir dizi oluşturuyorum. Sonra oluşan bu 10 kişilik dizi ile sorgu işlemi yaptırıyorum. Sonuç olarak kullanıcı takip ettiği kişi sayısı kaç olursa olsun, her sayfa yenilendiğinde takip ettiği kişiler arasından random olarak seçilen 10 kişiye ait linkler ana sayfada gösteriliyor.

Şuan için bu sorunu böyle çözdüm ama çok daha etkili bir algoritma yazılabilir. Örnek olarak kullanıcıların birbiriyle olan her türde etkileşimleri için istatistik tutabiliriz. Mesela başka birinin profiline kaç kere girdiği, onun kaç tane linkini veya listesini favoriye eklediğini, onun kaç listesinin veya linkinin url’ini kopyaladığı gibi istatistikler tutulabilir. Daha sonra etkileşimi en yüksek olduğu on kişinin paylaştığı linkleri ve listeleri çekebiliriz. Belli aralıklarla da etkileşimi düşük kullanıcıların linklerini ve listelerini araya katabiliriz.

Bu bahsettiğim algoritma haricinde birçok algoritma oluşturabiliriz. Projenin yeni versiyonunda bu algoritma kullanılabilir.

Kullanıcı Arama İşlemi

Kullanıcı arama işlemi için firestore bir özellik sunmuyor. Yani ismi “mehmet” olan birini aratmak istediğinizde, firestore kayıtlı kullanıcıların isimlerinin arasından bu aratmayı yapamıyor. Sadece ilgili stringe bire bir eşit olan stringleri sonuç olarak döndürebiliyor.

Bu yüzden araştırmalarım sonucunda şöyle bir yol olduğunu buldum. Biraz ilginç gelebilir ama en mantıklı yolun bu olduğuna karar verdim.

Firestore bire bir stringe eşit olan sonuçları getirebildiği için bu yöntem ile aratma işlemini şu şekilde bağdaştırabiliriz. Kullanıcı kayıt olduğunda kısa bir kod yardımıyla, kullanıcının adını ve kullanıcı adındaki boşlukları silip tüm harfleri küçük hale getirerek harf harf bölüyoruz. Ve çıkan tüm sonuçları bir diziye ekliyoruz. Bu diziyi firestore’da kullanıcı bilgilerinin arasında tutabiliriz.

Üyenin adı ve kullanıcı adı maxiumum 20 karakterden oluşacak şekilde ayarladım. Böylece bu dizi içerisine maximum 40 eleman alacaktır.

Aratma işleminde ise kullanıcı input alanına her karakter girdiğinde 1 saniye süre tanınıyor. O 1 saniye içerisinde yeni bir karakter girdiği takdirde yeni bir 1 saniye tanınıyor. Kullanıcı ne zaman karakter girmeyi bırakıp o 1 saniye dolarsa, o anda aratma işlemi veritabanında gerçekleşiyor.

Örnek kullanıcı “meh” yazıp bıraktı, sorgu işleminde içinde “meh” geçen isimler gösteriliyor.

Önerilen Etiketler

Sağ kısımda bulunan önerilen etiketleri dinamik olarak güncelleyebilmek için çeşitli yollar düşündüm. En son veritabanı kullanmadan dinamik olarak güncelleyebileceğim bir yol buldum. Kullanıcının takip ettiği kişilerin linkleriyle ilgili etiketler gösterecektim.

Öncelikle aynı konuları içeren etiketleri bir araya getirerek çeşitli etiket dizileri oluşturdum. Kullanıcının takip ettiği kişilere ait linkler ve listeler çekilince onların içerisindeki etiketleri bir diziye aktardım. Sonra bu etiketleri tek tek benim oluşturduğum etiket dizilerinde arattım. Bu etiketlerle eşleşen etiketler varsa onlara ait olan dizileri bir araya topladım. Daha sonra elde ettiğim etiketlerden random olarark altı tane etiketi dinamik olarak sağ taraftaki componentte listeledim.

Etiket dizilerini daha da büyütürsem, kullanıcıya daha ilgili etiketler gösterebilirim.

Bu Proje ile Neleri Detaylı Öğrendim?

Stourl.com’u geliştirirken birçok konuyu derinlemesine araştırıp bu konular hakkında derinlemesine bilgiler öğrendim. Ayrıca birçok sorunla da karşılaştığım için bu sorunların çözümü için de fazla araştırma yaptım. Her çözdüğüm sorundan sonra yeni bir olayın mantığını kavradım.

Öncelikle tasarım için Figma programını kullandığımdan çizim konusunda kendimi geliştirdim. Figma’da tasarımı component bazlı olarak tasarlamadım ama bu projeyi tasarlarken bu konuları da öğrenmiş oldum, hatalarımı gördüm. Bu projeden sonra yaptığım tasarımlarda component bazlı tasarım yapmaya dikkat ettim.

Vue-router, vuex kütüphanelerini detaylı olarak kullanmayı öğrendim. Veritabanı olarak Google Firestore kullandığım için bu konuda da oldukça bilgi sahibi oldum. Firestore’un dökümanı oldukça iyi hazırlanmış, kaç kere okuduğumu hatırlamıyorum

Bu projeyi kodlarken süreç içerisinde birçok yeni modül eklediğimden kod karmaşası çok oldu. Yeni versiyonda bu karmaşıklıkları düzeltip daha düzgün bir dosya yapısı oluşturacağım.

Stourl.com’u Geliştirirken Kullandığım Araçlar, Kütüphaneler ve Diller

  • Figma
  • Vue.js
  • Vue-Router
  • Vuex
  • Vue-Toast
  • Vuelidate
  • Vue-md5Converter
  • Firebase Authentication
  • Firebase Firestore
  • Firebase Storage
  • Scss
  • Jquery — Parallaxie

Stourl’un Yeni Sürümünde Olacak Özellikler

Stourl’u daha da geliştireceğim için başka özellikler de ekleyeceğim. Yeni gelecek özelliklerden bazılarını şöyle sıralayabilirim:

  • Özel link ve liste Ekleme
  • Şifreli link ve liste (şifreyi bilen kullanıcılar görebilecek)
  • Link ve liste istatistikleri
  • Link ve liste bağlantı karekodu
  • Chrome eklentisi (eklenti ile stourl.com’u açmadan link kaydedilebilecek)
  • Profil için kategorilendirme
  • Linkleri dışarı aktarma

Sonuç

Sonuç olarak Vue.js ile büyük ve birçok modülü olan bir proje geliştirme fırsatı elde ettim. Her çıkan sorunu araştırdığımda genellikle Stackoverflow sayesinde sorunları çözüyordum. Çözdüğüm sorunları Stackoverflow’da bookmarks kısmına ekledim. Stourl’u geliştirme aşamasında yaklaşık 45 sorunu Stackoverflow yardımıyla çözmüşüm.

Kısacası Stourl bana o kadar çok şey kattı ki, artık daha kompleks projelerde rol alabileceğime inanıyorum.

Uzun bir yazı oldu, yenilerinde görüşmek üzere

https://stourl.com

--

--