Bir İş Görüşmesinde Detaylı İstenen Proje Bölüm1

Selamlar;

Bugüne kadar hep teknik konular üzerinde kodlar yazdık. Ama gerçek hayat dışarıda. Bugün biraz da olsa gerçek yaşamdan bir kesit olarak bir iş görüşmesinde birebir karşılaştığım, firmanın benden istediği bir projeyi kodlayacağız. Normalde bu tarz görüşmeleri kabul etmememe rağmen sırf makalesini yazıp sizle de paylaşmak için bir hafta sonumu verip yazdım. Zaten projeyi teslim etmem için bana verilen süre de 48 saatdi. Sanırım bu zamandan sonra proje kendi kendini imha ediyor:)

Öncelikle gelin neler isteniyor maddeler halinde yazalım. Not: Tüm istenenler yani dökümanlar ingilizce idi. Ben aşağıya madde madde tükçelerini yazıyorum:

Kurların oranlarının gösterildiği TCMB servisine ilgili linkden ulaşabilirsiniz: http://www.tcmb.gov.tr/kurlar/kur2015_tr.html

Yapılması Gereken İşler:

  1. Birkaç XML’i download ediniz.
  2. Bu Xml dosyaları Parse ediniz.
  3. Basit bir UI form hazırlayıp gelen “Kur İsmlerini” Türkçeden İngilizceye çevirerek gösteriniz. TUR->ENG. Örnek(ABD DOLAR->USA Dollar  İNGİLİZ STERLİNİ -> Great Britain Pound)
  4. Dataları sürekli Database’den dinleyip güncellenenleri, Jquery kullanarak Mvc bir sayfada gösteriniz.
  5. Dataları sürekli Database’den dinleyip güncellenenleri, SignalR kullanarak Mvc bir sayfada gösteriniz.

Aşşağıdaki Teknolojileri Kullanmak Artıdır:

  • Asp.Net Mvc
  • Entity Framework
  • Jquery
  • SignalR
  • Sql Express/Server
  • Design Pattern usage

Önemli:

  1. Projeyi tamamen bitirmenizi beklemiyoruz. Çözüme yaklaşımınızı görmek istiyoruz. Uygulamaya yorumlarınızı istediğiniz gibi eklemekde özgürsünüz.
  2. Toplam 48 saat süreniz vardır. Eğer uzayacak veya daha fazla zaman isterseniz bizi bilgilendirmekte özgürsünüz.

İyi şanslar.

Şimdi istenenleri gördüğümüze göre ben değişen kurları yakalama adına güncel kurların döndüğü sayfayı parse ettim. Yani: http://www.tcmb.gov.tr/kurlar/today.xml kullandım. Böylece bu sayfa üzerinden anlık değişen kurları yakalamak bana daha anlamlı geldi.

currency

1-) İlgili today.xml’i download ettikten sonra bir text editor’ü ile açıp aşağıdaki stylesheet tanımlama satırnı temizleyip yeniden kaydettim. Burada amaç Xml sayfasını, yukarıda görüldüğü gibi sade hale getirmektir. Böylece element adları hem daha kolay hem de ayrıntılı bir şekilde gözükmektedir.

2-) Bu projede CodeFirst kullanılmıştır. Buna göre servisden dönen alanlara göre, DAL projesi altında poco nesnesi aşağıdaki gibi oluşturulur. Tablonun adı “CurrencyReport“‘dur.”[Table(“”)]” attribute ile atanmıştır. Arama işlemi “CurrencyName“‘e göre yapıldığı için Index “[Key]” attribute’ü ilgili kolona atanmıştır.

CurrencyReport.cs:

CurrencyContext.cs: Database adı “Currency” olarak aşağıdaki DbContext’de tanımlanmıştır. Ayrıca tablodaki fieldlara ait configuration propertyler “OnModelCreating()” methodunda aşağıdaki gibi tanımlanmıştır.

İlgili Poco’dan oluşan Currency Database’indeki CurrencyReport tablosu aşağıdaki gibidir:

tbl

3-) Şimdi sıra geldi ilgili Xml’i parse edip database’e atmaya. Bu işlem için CurrencyWindowsServices adında bir WindowsService projesi oluşturulur. Amacı belli zaman aralıkları ile (1/dk) ilgili servise gidip kontrol işlemi yapmasıdır.

Program.cs: İlgili servis’in Debug modda test edilebilmesi için  “#if DEBUG”  ile uygulamanın debug modda çalıştırılması durumunda Service1() adlı sınıf çağrılmaktadır. Release modda ise servis normalde çalışması gerektiği gibi  işlemleri başlatmaktadır.

Service1.cs(Timer): Aşağıda görüldüğü gibi dakikada 1 kere(60000) çalışacak timer tanımlanmış ve her çalışmasında “GetCurrencyData()” methodu asenkron olarak çağrılmıştır. Önemli bir nokta: Windows service uygulamalarda timer runtime’da aşağıda görüldüğü gibi yaratılmalıdır. Sürükle bırak şeklinde design time’da eklenen timer windows service’de hatalı çalışır.

GetCurrencyData(): Timerla her dakikada bir çağrılan method öncelikle ilgili “today.xml”‘i “WebClient()” ile asenkron olarak donwload etmekte daha sonra “XmlDocument” ile bir “DataSet“‘e doldurmaktadır.

  1. Databasede herhangi bir kaydın olup olmadığı durumuna bakılarak, boş olması durumunda tüm kayıt tek tek gezilerek parse edilir ve “CurrencyReport” tablosuna doldurulur. Daha sonra Entitiy Framework kullanılarak ilgili tablo kaydedilir. Son olarak her eklenen yeni kayıt “NewDatas” listesine eklenir ve daha sonra bahsedeceğimiz “Currency” signalR Hub sınıfındaki “FillData()” methodunu “HubConnection” ve “IHubProxy” nesneleri yardımı ile parametre olarak gönderilir. Bu sayede “FillData()” methodu asenkron olarak tetiklenmesi ve tüm clientlarda yeni eklenen verilerin real time olarak gözükmesi  sağlanır.
  2. Eğer databasede önceden kayıt var ise performansı arttırmak için çekilen tüm datalar “List<CurrencyReport> cacheDatas” türünde bir Liste’ye atılır. Tabi eğer Liste null ise bu işlem gerçekleştirilir. Nesnenin amacı servisden çekilen datalar ile önceden kayıtlı olan dataların birbirleri ile kıyaslanıp değişen dataların tespit edilmesi ve bu sayede her seferinde önceki datalar için database’e gidilmemesinin sağlanmasıdır. Böylece performance artışı sağlanmıştır. Yeni çekilen her bir data tek tek gezilip “CurrencyReport” modeli doldurulmakta ve “isDataChange()” methodu ile linq kullanılarak kayıtlı datalara göre değişiklik olup olmadığna bakılmaktadır. Eğer değişiklik var ise “changeDatas” listesine ilgili değişen kayıtlar eklenmektedir. Daha sonra herbir değişen data tek tek CurrencyRepeort tablosunda bulunarak güncellenir. Sadece değişen datalar “Currency” signalR Hub sınıfındaki “FillData()” methodunu “HubConnection” ve “IHubProxy” nesneleri yardımı ile parametre olarak gönderilerek asenkron olarak tetiklenmesi ve tüm clientlarda sadece değişen dataların real time olarak güncellenmesi performans açısından yapılan önemli bir adımdır. Ayrıca eski datalar değiştiği için “FillCache()” methodu ile cache nesnesi olan “changeDatas” güncellenmiş yani en son datalar ile databeseden tekrardan doldurulmuşdur. Böylece bir sonraki kıyaslama zamanında servisden gelen yeni datalar, güncellenmiş enson datalar ile karşılaştırılabilecektir.
  • HubConnection: SignalR sınıfının bulunduğu sunucuya bağlanmayı sağlar.
  • IHubProxy: İşlem yapılacak SignalR hub sınıfına erişimi sağlar. “Invoke()” methodu ile ilgili sınıfın methodu triger edilir yani tetiklenir. Böylece bağlı olan clientlardaki javascript function’ı server side taraftan client side tarafa doğru olmak üzere erişilip call edilmiş olunur.
  • HubConnection.Start() methoduna dikkat edilir ise asenkrondur. Nedeni ilgili Hub sunucusuna erişimin ne kadar süreceğinin bilinmemesidir. Doğal olarak “GetCurrencyData()” methodunun da asenkron olmak zorunludur.

changeDatas, cacheDatas, FillCache() ve isDataChange(): Yukarıda kullanılan listeler ve methodlar aşağıda görüldüğü gibi tanımlanmıştır.

  • changeDatas” sadece değişen dataların tutulduğu bir Listedir. Bu liste sayesinde data güncellemesi olduğu zaman sadece bu liste içindekiler gezilip tek tek güncellenmektedir. Dikkat edilirse: Performance amaçlı tüm datalar güncellendikten sonra “entity.SaveChanges()” yapılmış hepsi için bir kere database’e gidilmişitir. Ayrıca sonradan bahsedeceğimiz signalR hub sınıfına sadece değişen datalar(changeDatas) gönderilerek performans artışı sağlanmıştır.
  • “cacheDatas” enson kur bilgisinin tutulduğu listedir. Yeni kur bilgisi geldiği zaman hangi datanın güncellendiğinin anlaşılması için database’e değil database’in son güncel halinin tutulduğu “cacheDatas”‘a bakılır. Eğer değişen data var ise “cacheDatas”‘da güncellenir.
  • FillCache() methodu “cacheData” listesini doldurur.
  • isDataChane() methodu gelen kur datasının ilgili kolonlor ile önceki dataya göre, linq kullanarak değişip değişmediğine bakılır.

Ayrıca aynı uygulama Windows Service yerine Azure tarafında, Cloud Service olarak aşağıdaki gibi alternatif bir çözüme gidilebilir.

Solution’a Cloud sekmesinden Azure Cloud Service aşağıdaki gibi eklenir:

cloud

Arkada çalışacak yapı Worker Role olarak aşağıdaki gibi eklenir.

worker

WorkerRole.cs: Kodlar yukarıda yazdığımız Windows Service’e büyük çoğunlukla benzemektedir.

Böylece ilgili servis’in 1/dk’da pars edilip, eğer kayıt var ise değişenlerin, yok ise tamamının database’e güncellenerek yada kaydedilerek, signalR Hub sınfına gönderilmesinin, Windows Service ve Azure Cloud Servis yaklaşımlarını inceledik.

Son olarak database’e kaydedilen bu verileri dışarıya bir servis yardımı ile verelim. Bu işlem için aşağıdaki gibi CurrencyService adında yeni bir WebApi servisi yazılmıştır.

WebApi

CurrencyController.cs: Aşağıdaki servisde “GetAllCurrency()” methodu ile “CurrencyReport” tablosundaki tüm data Linq ile çekilerek döndürülmektedir. Burada herhangi bir cache yapısının bulunmamasındaki amaç, esas cache’in bu servisi kullanan yapılarda olması ve eğer gerçekten servise bir sorgu atıldı ise gerçek zamanlı en son data bilgisinin istenmesidir.

Geldik gerçek hayattan kesitli makalemizin  ilk bölümünün sonuna. Bu bölümde code first yardımı ile DataBase’i oluşturduk. Sonra ilgili servisi belli zaman aralıkları ile parse edip database’e insert eden bunu da signalR websocket teknolojisini kullanarak tüm clientlara duyuran windows servisi ve alternatif çözüm olarak azure cloud servisini yazdık. Son olarak da ilgili kurların bilgisini veren WebApi servisini kodlayıp konunun ilk bölümünü tamamladık.

Makalenin devamında görüşmek üzere hoşçakalın.

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

13 Cevaplar

  1. Sedat dedi ki:

    1 kasa domates alıp satarsak ve bu satıştan kazanılan para ile 1 kasa domates alacak kadar kazanç saglarsak,aynı performans ve azimle tekrar satış yaptığımızda 4 kasa domates kazanmış oluruz. İf kazandığımız parayı yemeden ve kimselere kaptırmayan 4 kez dondurursek toplamda 16 kasa domatesin olur, 4.günün sonunda 16 kasa domates ten 800 TL kazanırsak ve bunu 7 kez yaparsak 28 günde yaklaşık 5600 TL kazaniriz..
    Else köleliğe devam

    Saygılarımla

    • borsoft dedi ki:

      Ben o kasadaki domateslerin 1/4’ü ile menemen yaparım. Böylece 5600 değil 4200TL kazanırım. Böyelece hem karnım doyar hem de kafam rahat olur:)

  2. mehmet dedi ki:

    Hep düşünmüşümdür gerçek hayattaki projelerde neler isteniyor diye. Çokta aman aman şeyler değilmiş.Sanıyordum ki angulara takla attırıp , sql’i amuda kaldıracaz vs diye ama öyle değilmiş. Bu arada teşekkürler hocam.

  3. Taylan dedi ki:

    Tcmb den dovizleri web client ile okuyup daha sonra dataset icerisine atmak yerine, linq to xml ile okumak, hatta direk dataset ile read xml yapmak daha mantikli.

    • borsoft dedi ki:

      Selamlar Taylan;
      Bir işi yapmanın birçok farklı yolu vardır. Siz de belirtiğiniz yolların neden daha mantıklı olduğunu da söylerseniz çok daha yararlı bir yorum olabilir. Daha mı performaslı, daha mı anlaşılır, yoksa daha mı hızlı.
      Bunlar gibi nedenler ile konuya yaklaşırsak bence zaten amacımız olan daha iyiye ulaşmak için bir adım daha atmış oluruz.

      İyi çalışmalar.

  4. Yunus dedi ki:

    Aklıma takılan soruların cevaplarını bu makalede buldum.Teşekkürler hocam

  5. ömer yılmaz dedi ki:

    Dediğiniz gibi bir sorunun birden fazla çözüm yolu var. Paylaşmak için emek ve vakit harcadığınız için teşekkürler.

  6. Yunus dedi ki:

    Bora hocam selamlar,

    Çok doyurucu bir makale olmuş ve izninizle blogunuzdaki yazılarınızı pdf haline getirip kaydediyorum.

    Çok teşekkürler.

    • borsoft dedi ki:

      Selamlar Yunusi

      Teşekkür Ederim.
      Sonunda hepsini yaparsan benle de bir dropbox, onedrive Url’i paylaşarısan sevinirim :)

      Kolay Gelsin..

  7. Tagi dedi ki:

    Hocam , teşekkür ederim.Çok faydalı oldu.
    Sizi Azerbaycandan takip ediyorum.
    Saygılar..

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.