29 Kasım 2013 Cuma

Kindle

Birseyler ogrenme asamasindayken okunan kitap, web sayfasi  ve dokuman sayisi inanilmaz boyutlarda olabiliyor. Bunlarin bazen bir kismi bazen tamami lazim olurken uzerine not almak, post-it yapistirmak, altini cizmek gerekebiliyor. (Belki de ben ozellikle notlar alarak calisan birisi oldugum icin en azindan). Kitap boyutlari malum bir de uzerine ayni anda birkac konuyu paralel calismak gereken bir doneme girince cantamda laptop'a yer kalmadi. Kitaplar, calisma notlari ve print edilmis web sayfalarindan olusan bir obekle dolasir hale geldim.

Tam bu sirada mailime "kindle fire" in ozel bir indirimde oldugu haberi geldi.  Zaten kindle sahibi birisi olarak faydalarina hakimim. Ama bendeki model roman okumak icin cok ideal. Konu pdf dosyalari ve web sayfalari olunca yetersiz kaliyor. O yuzden bu modelin de siparisini verdim.

Kindle fire bir cesit tablet kivaminda hazirlanmis. kamerasi da olsa neredeyse tablet diyebiliriz hatta. Kendi uzerinde pdf okumak icin bir aplikasyon olmasina ragmen bana gereken ekstra ozellikler icin ez pdf reader aplikasyonunu da indirdim. bu aplikasyon ile istediginiz bolumlerin altini cizmek, sayfa ustune not almak  cok kolay.

Readability aplikasyonunu da indirerek web siteleri ile olan bagimi daha bir saglamlastirdim. Readability once bilgisayarinizdaki web browser'a kuruluyor. Sonra gordugunuz bir web dokumanini sonradan okumak uzere saklamak istediginizde browser'daki ikonuna tiklayip "Read Later"i seciyorsunuz. Program webdeki dokumani e-book olarak okumak icin tekrar formatliyor (ki cogu yerde cok cok basarili) ve arsivine koyuyor. Boylece kindle'da bu aplikasyonu actiginizda dokuman karsinizda neredeyse e-book formatinda sizi bekliyor oluyor.

Bunlarin ustune ES File Explorer kurdum. Bu aplikasyon bilgisayardaki file explorer'i kindle uzerinde kullanmanizi sagliyor. Malum Kindle'da defaul gelen boyle bir aplikasyon yok. Ama ES bambaska bir yonu ile beni buyuledi. Butun cloud disklerinizi uzerine tanimlayip sanki bilgisayarinizdaymiscasina birinden digerine gecisler yapip dosya kopyalayabiliyorsunuz. Skydrive, dropbox, gDrive, Ubuntu 1 gibi cloud drive'lar bu sayede cok kullanisli hale geliyor.

"send to kindle" ile ugrasmadan mesela "Skydrive" uzerine koydugunuz bir kitabi kindle'da direk acabiliyorsunuz.

Bunlarin yanisira "pocket" ile readability'nin benzeri bir yapi kurmak da mumkun.

Hepsi bir araya gelince asagi yukari 100 kitaplik bir referans arsivi, onlarca web sayfasi ve dokumandan olusan bir calisma ortami tek bir cihazda birlesti.

Ekonomik bir cozum olarak fena degil ama sarj suresi tabi ki eski kindle kadar degil ve bir sekilde surekli sarja yakin olmaniz lazim. Eger ekonomi degil rahatlik ariyorum diyorsaniz ipad mini tum bunlardan daha guzel bir cozum de olabilir. 

30 Ekim 2013 Çarşamba

BDD - Cucumber

Projelerin icinde bogustugum donem icinde yazilim dunyasi oyle cok degismis ki simdilerde kendime programci demeye utanir hale geldim. Bildigim herseyi sildim simdi yeniden bir ogrenci edasiyla herseye yeniden baslamanin heyecani ve ogrenecek bir suru konunun bilinci ile meslege yeniden basladim. Zaten bu asamada ya bunu yapacaktim ya da kariyer degistirecektim. Zira bilgisayar programcilarinin kendilerini yenilemediklerinde 5 sene icinde bir hic'e donustugunu cok iyi biliyorum.


Size proje gelistirmede gelinen son noktalardan birisi olan BDD (Behaviour Driven Development) konusunu anlatmaya calisacagim. Bundan birkac hafta oncesine kadar bu konu hakkinda hic bir fikrim yoktu. Hatta hic duymamistim. 

Bildigimiz ogrendigimiz hatta ogrettigimiz, proje gelistirme yontemi su sekilde idi. 
1 - Analiz 
2 - Tasarim ve Planlama 
3 - Gelistirme
4 - Test
5 - Teslim 
6 - Bakim (yani tekrar 1. adimdan baslayan bir dongu) 

Bu yontemde sorun olan nokta Analiz ve Teslim sirasinda musteri (muhatap ile ayni sirkette iseniz ic musteri de diyebilirsiniz ama projeyi kullanacak taraf musteridir) ile kurdugunuz temaslarda net bilgileri alma zorlugu ve teslimde yasanan problemlerdi. Yazilimcilar musterinin dilini, musteri yazilimcinin dilini anlamadigi icin arada normalde olmasi gereken BA (Business Analyst) unvanli adamlar olmasi gerekirdi. Ben Turkiye'de pek rastlamadim ama normalde var bu unvan. 

Bunlar yapilacak isi dinleyip analiz edip etkilenecek diger yapilari inceleyip programciya projeyi yapilacak is parcalari seklinde ve adimlar halinde sunan adamlar. 

Iste BDD tam bu noktada devreye giriyor ve yukaridaki sistemdeki siralamalari degistiriyor. 

Analiz sirasinda, aslinda teslim'de istenen teslim kriterlerini ortaya koyarak bir nevi kabul testi olusturuyor ve projeyi bastan itibaren kabul kriterleri icinde gelistirmek uzere bir cerceve ciziyor. 

BDD ile duzyazi seklinde musterinin rahatlikla okuyunca anlayacagi is parcalari olusturuyor ve bunlarin uzerinde seneryolar uretiyoruz. Her biri rahatlikla okunabilen parcalar oldugundan (gercekten kod icermiyor) musteri ile mutabakat saglamak adina cok faydali bir adim. Ayni zamanda bu duzyazilar sizin testlerininzin sablonu ve TDD (Test Driven Development) icin bir cati anlamindalar. 

Boylece gelistirmedeki yontem soyle birseye donusuyor. 
1 - Analiz
2 - Tasarim, dokumantasyon ve test planlama
3 - Gelistirme ve Test
4 - Teslim 
5 -  Bakim

BDD icin TDD'yi de anlamak gerekiyor. TDD az da olsa kod icerdigi ve okunurken tam bir duzyazi olusturmadigi icin biraz daha programciya yakin bir kavram ama BDD tam ortada konumlanmis durumda. 

BDD icin en yaygin programlardan Cucumber ile tanismaya hazir miyiz ? 
http://cukes.info/ sitesinden ulasabileceginiz cucumber Ruby icin yazilmis olsa da .NET icin de kullanabilmenizi saglayan http://www.specflow.org/ gibi siteler de mevcut. Baska diller icin nasil kullanildigini google ile biraz arama yaparak bulabilirsiniz.

Gecen hafta tanistigim Matt Wynne Cucumber uzerine yazilmis iki kitabin da yazari.

Turkiye'de nasil elde edeceginizi bilemiyorum ama bu kitaplara ulasmak icin ipuclari bu blogda mevcut.

Kabul testleri yazildiginda dogal olarak hata verecektir. Cunku henuz kod yazilmamistir ancak musteriye de yazilimciya da sonucta ne olacagini anlatirlar.
Unit Test (birim test) kavrami ile karistirilmamasi gerekir. Birim test'i birseylerin dogru yapilmasini saglarken kabul testleri dogru birseylerin yapilmasini saglar. 

Testlerde onemli nokta da takimdaki herkes tarafindan anlasilacak ortak bir dil kullanilmasi gerektigidir. Cucumber'i guclu kilan yon de takimdaki herkes tarafindan testlerin kolaylikla yazilmasini saglayan dil yapisidir.

Asagida bir ornegini goruyorsunuz. Cucumber tarafindan kritik kelimeler bold ve kirmizi isaretlenmistir. Dilerseniz Turkce de kullanabilirsiniz. Nasil Turkce kullanilacagi hakkinda bilgi icin luten asagidaki linke bakiniz.

https://github.com/cucumber/cucumber/wiki/Spoken-languages
Feature: Sign up
  Sign up should be quick and friendly.

  Scenario: Successful sign up
    New users should get a confirmation email and be greeted
    personally by the site once signed in.
    Given I have chosen to sign up
    When I sign up with valid details
    Then I should receive a confirmation email
    And I should see a personalized greeting message

  Scenario: Duplicate email
    Where someone tries to create an account for an email address
    that already exists.
    Given I have chosen to sign up
    But I enter an email address that has already registered
    Then I should be told that the email is already registered
    And I should be offered the option to recover my password
Metin dosyalarinda basit birkac yazim kurali gecerlidir ki bu kurallara Gherkin deniyor

Bir diger fayda da kodlarin gercekten ne yaptigini yansitan dokumantasyonun (mecburen) guncel ve senkronize olmasi durumudur. Cunku ne degisiklik yapilmis olursa olsun bu dokumantasyon guncel olarak devam edecektir.

Nasil calistigina gelince; herseyden once cucumber bir komut satiri programidir. Sonu features diye biten metin dosyalarindan spesifikasyonlari okur. Senaryo bazinda testleri calistirir. Her senaryo Cucumber'in calisacagi test adimlarindan (step definition) olusur, boylece cucumber ne yapilacagini anlar. Bir seneryo icindeki adim tanimlari tek tek islenip hata ile karsilasilmazsa bir sonraki senaryoya gecerek teste devam edilir.

Cucumber calistirildiginda belli bir klasor duzeni icinde belli dosyalari gormek istiyor.
TestProjesi altinda klasor ve dosya yapilanmasi su sekilde olacaktir


Adim tanimlarini olusturma 

Basit bir toplama islemi icin su sekilde bir features dosyasi olusturup komut satirinda cucumber yazdiginizda 
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
    Then the output should be "4"     

cucumber size asagidaki sekilde bir cikti verecektir.
cucumber
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
    Then the output should be "4"  
1 scenario (1 undefined)
3 steps (3 undefined)
0m0.003s
You can implement step definitions for undefined steps with these snippets:
Given /^the input "([^"]*)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end
When /^the calculator is run$/ do
  pending # express the regexp above with the code you wish you had
end
Then /^the output should be "([^"]*)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end
If you want snippets in a different programming language,
just make sure a file with the appropriate file extension
exists where cucumber looks for step definitions.

Ortada yesil ile gosterdigim bolum cucumber'in bekledigi adim tanimlarinin bir ornegidir. bu bolumu kopyalayip features dizini altina olusturacaginiz step_definitions klasorunde bir ruby (veya hangi dil icin kullaniyorsaniz o dilin) dosyasina yapistirin.

Simdi cucumber calistirildiginda artik bize adim dosyasi uzerinde hangi adimda test'in kirildigini anlatmaya baslayacaktir.

Adim tanimlari icinde bol bol Regular Expression kullanildiginin farkindasinizdir. Bu da baska bir yazinin konusu olacak simdi ilk testi duzenliyoruz. Basitce verilen parametreyi degiskene atadik.

Given /^the input "([^"]*)"$/ do |input|
@input = input
end
cucumber bu asamada calisinca cikti farkli olacaktir.
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
      TODO (Cucumber::Pending)
      ./features/step_definitions/calculator_steps.rb:9
      features/adding.feature:5
  Then the output should be "4"

1 scenario (1 pending)
3 steps (1 skipped, 1 pending, 1 passed)
0m0.002s
evet cucumber testlerin 1. adiminin gecildigini gosteriyor artik. Adim tanimlarina donup 2. adimi so sekilde duzenliyoruz.

When /^the calculator is run$/ do
    @output = `ruby calc.rb #{@input}`
    raise('Command failed!') unless $?.success?
end
tekrar cucumber calistirildiginda
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    ruby: No such file or directory -- calc.rb (LoadError)
    When the calculator is run
    Command failed! (RuntimeError)
    ./features/step_definitions/calculator_steps.rb:10
    features/adding.feature:5
    Then the output should be "4"

Failing Scenarios:
cucumber features/adding.feature:3
1 scenario (1 failed)
3 steps (1 failed, 1 skipped, 1 passed)
0m0.027s
hata degisti artik boyle bir dosyanin olmadigi hatasini aliyoruz.

Mantik bu sekilde herhangi bir, asamada cucumber'i calistirarak bir sonraki asamda ne yapilmasi gerektigini goruyor ve adim adim projenizi ilerletebiliyorsunuz. Boylece her adimda hem kabul testine sadik kaliyor hem de istenilenlerin yapildigindan emin olarak ilerleyebiliyorsunuz.

Bu yazi kalabaligindan ziyade sorunu direk gormek istediginizde asagidaki gibi cucumber'i calistirabiliyorsunuz
cucumber --format progress
o zaman da cikti olarak asagidaki goruntuleniyor.
.ruby: No such file or directory -- calc.rb (LoadError)
F-

(::) failed steps (::)

Command failed! (RuntimeError)
./features/step_definitions/calculator_steps.rb:10
features/adding.feature:5

Failing Scenarios:
cucumber features/adding.feature:3 # Scenario: Add two numbers

1 scenario (1 failed)
3 steps (1 failed, 1 skipped, 1 passed)
0m0.023s
Program olmadan testlerin gecilebildigine dikkat etmissinizdir. testlerin bazilarinin gecilmis olmasi onemli degil sonucta tum projenin testi hatasiz bitirmesi onemli.
When /^the calculator is run$/ do
    @output = `ruby calc.rb #{@input}`
    raise('Command failed!') unless $?.success?
end

Birkac feature ornegi daha verelim
Feature: Feedback when entering invalid credit card details In user testing we've seen a lot of people who made mistakes entering their credit card. We need to be as helpful as possible here to avoid losing users at this crucial stage of the transaction.

Background:
  Given I have chosen some items to buy
  And I am about to enter my credit card details

  Scenario: Credit card number too short
    When I enter a card number that's only 15 digits long
    And all the other details are correct
    And I submit the form
    Then the form should be redisplayed
    And I should see a message advising me of the correct number of digits

  Scenario: Expiry date invalid
    When I enter a card expiry date that's in the past
    And all the other details are correct
    And I submit the form
    Then the form should be redisplayed
    And I should see a message telling me the expiry date must be wrong
Ozelliklerin yazildigi Gherkin dilindeki anahtar kelimeler (ingilizce olanlari)
• Feat ure
• Background
• Scenario
• Given
• When
• Then
• And
• But
• *
• Scenario Outline
• Examples
Turkceleri ise

         "feature": "Özellik",
         "background": "Geçmiş",
         "scenario": "Senaryo",
         "scenario_outline": "Senaryo taslağı",
         "examples": "Örnekler",
         "given": "*|Diyelim ki",
         "when": "*|Eğer ki",
         "then": "*|O zaman",
         "and": "*|Ve",
         "but": "*|Fakat|Ama"
Sadece Gherkin'de yazilanlarin dogrulugunu test etmek ama programi test etmek istemediginizde asagidaki komutu verebiliyorsunuz.
cucumber test.feature --dry-run
yukaridaki anahtar kelimelerin fonksiyonlarina gelince

Feature 

Pek bir anlam ifade etmiyor sadece ozelligin aciklamasinda kullanilan terimlerin basina geliyor ve aciklamalar birkac satirdan olusabiliyor.

Ardindan su anahtar kelimelerden biri gelmek zorunda
• Scenario
• Background
• Scenario Outline

Nereden baslanacagini bilemediginiz ozellikler icin soyle bir kalip kullanmak faydali olabilir

In order to <meet some goal>
As a <type of stakeholder>
I want <a feature>
Bir de yine de aralara yorum yazmak isterseniz # isaretini kullanabilirsiniz. 

Scenario

istedigimiz davranis(lar)in anlatilmasi icin bunu kullaniyoruz. Senaryolar projenin sinirlarini cizmek icin kullanilir ve su sekilde bir yol izlerler.
1 - Sistemi belli bir duruma getir
2 - durt, gidikla birseyler yap
3 - Yeni durumu incele

Senaryolari yazarken cok onemli bir husus var : 

Her senaryo mantikli olmali ve bagimsiz olarak tek basina calistirilabilir olmalidir. 

Yani bir senaryoda para yatirip digerinde cekmeniz isin dogasina aykiri. (hata olarak degerlenmiyor ama yanlis)

Senaryo isimlerinin duzgun verilmesi zaman kazanmak icin onemlidir. Boylece feature dosyasi icindeki kodlari okumadan probleme odaklanma, sonradan bakim yapmayi kolaylastirma gibi faydalar yaratacaktir.

Given, When , Then

Senaryolarda izlenecek yolu belirlemede kullanilirlar.

Scenario: Successful withdrawal from an account in credit
  Given I have $100 in my account # the context
  When I request $20 # the event(s)
  Then $20 should be dispensed # the outcome(s)

And, But

Senaryolardaki adimlari artirmak icin killanilabilecek yapilardir. Sadece okunabilirligi artirmak icin kullanilir . Ornegin asagidaki iki senaryo birbirinin aynisidir. Hatta bunlarin tamami yerine * kullanmak da mumkundur.

Scenario: Attempt withdrawal using stolen card
  Given I have $100 in my account
  But my card is invalid
  When I request $50
  Then my card should not be returned
  And I should be told to contact the bank


Scenario: Attempt withdrawal using stolen card
  Given I have $100 in my account
  Given my card is invalid
  When I request $50
  Then my card should not be returned
  Then I should be told to contact the bank

Her bir asamanin yerinin dogru anlasilmasi icin yandaki sekil aciklayici olacaktir. 

Birkac Ipucu

Given a User "Michael Jackson" born on August 29, 1958
And a User "Elvis" born on January 8, 1935
And a User "John Lennon" born on October 9, 1940

Yerine su sekilde kullanimlar mumkun

Given these Users:
| name                  | date of birth         |
| Michael Jackson | August 29, 1958  |
| Elvis                   | January 8, 1935   |
| John Lennon      | October 9, 1940   |

veya
Then my shopping list should contain:
| Onions |
| Potatoes |
| Sausages |
| Apples |
| Relish |

Then I should see a vehicle that matches the following description:
| Wheels | 2 |
| Max Speed | 60 mph |
| Accessories | lights, shopping basket |



Sonucta size tamamini veya butun ipuclarini gosteremesem de mumkun oldugunca BDD ve Cucumber konusunu aktarmaya calistim. Bu arada bu yazida cokca yararlandigim Matt Wynne ve Aslak Hellesøy'un The Cucumber Book kitabini tekrar tavsiye ediyorum


Neden mi cucumber? Testleri gectikce yazilar yesile dondugu icinmis. 
Turkce kullanmak icin cucumber --i18n tr kullanabilirsiniz

23 Ekim 2013 Çarşamba

Performans Problemi

Bu arada yeni bilgilerle bogusurken kurs baslamadan once bitirdigim bir web sitesinin sahibinden surekli telefon ve mail ile sitenin yavasligindan sikayet gelmeye basladi. Siteye ben girdigimde herhangi bir sorun ile karsilasmadim. Hatta oldukca da hizliydi diyebilirim. Anlam veremedim ama kafama da takildi. Sonra aksam tekrar baktigimda ilk giris sirasinda gercekten yavas oldugunu ama sonrasinda hizlandigini gordum.

Once browser cache kullanmaya basliyor herhalde dedim ama farkli bilgisayar farkli browser ile denedigimde de hizliydi. sonra hosting isi yaptigim zamanlarda IIS uzerinde "keep alive" ayarinin oldugu geldi aklima.

Biraz konuyu arastirinca sorunun, 20 dakika kimse siteye girmezse aplikasyonun askiya alinmasi ve sonra ilk giren ile aplikasyonun tekrar yuklenmesinde kaybedilen zamandan oldugunu farkettim.

Ilk cozum tabi ki hosting'de bu ayarin kaldirilmasiydi. Ancak malesef boyle bir secenek yoktu. O zaman ikinci secenek olan "siteye periyodik olarak istek gondererek hayatta tutmak" ustune yoneldim.en kolay yolu da istatistik amacli programlardi. Bunun icin yaptigim arastirmada http://my.pingdom.com sitesini buldum

 1 site icin ucretsiz olan hizmetine kayit olarak sitenin hem uptime, hem response time olarak 5 dakikalik araliklarla istatistiklerini almaya basladim. Hem de herhangi bir sorunda bana mail atmasini ayarlayarak siteyi bir kademe daha garantiye aldim.

Bunlarin disinda bir baska oneri de sorunu kodla cozmekti.
Yayindan kaldirilmis ama arsivde bulunan bir sitede asagidaki gibi bir kod vardi.

   private KeepAlive(string applicationUrl)
     {
         _applicationUrl = applicationUrl;
         _cacheKey = Guid.NewGuid().ToString();
         instance = this;
     }

     public static bool IsKeepingAlive
     {
         get
         {
             lock (sync)
             {
                 return instance != null;
             }
         }
     }

     public static void Start(string applicationUrl)
     {
         if(IsKeepingAlive)
         {
             return;
         }
         lock (sync)
         {
             instance = new KeepAlive(applicationUrl);
             instance.Insert();
         }
     }

     public static void Stop()
     {
         lock (sync)
         {
             HttpRuntime.Cache.Remove(instance._cacheKey);
             instance = null;
         }
     }

     private void Callback(string key, object value, CacheItemRemovedReason reason)
     {
         if (reason == CacheItemRemovedReason.Expired)
         {
             FetchApplicationUr();
             Insert();
         }
     }

     private void Insert()
     {
         HttpRuntime.Cache.Add(_cacheKey,
             this,
             null,
             Cache.NoAbsoluteExpiration,
             new TimeSpan(0, 10, 0),
             CacheItemPriority.Normal,
             this.Callback);
     }

     private void FetchApplicationUrl()
     {
         try
         {
             HttpWebRequest request = HttpWebRequest.Create(this._applicationUrl) as HttpWebRequest;
             using(HttpWebResponse response = request.GetResponse() as HttpWebResponse)
             {
                 HttpStatusCode status = response.StatusCode;
                 //log status
             }
         }
         catch (Exception ex)
         {
             //log exception
         }
     }
}

Ne yaptigina gelince.
cache'ye 10 dakikaligina bir obje koyuyor, 10 dakika doldugunda bu obje sitedeki herhangi bir sayfayi cagiriyor. Sayfa cagirilinca tekrar obje olusuyor ve boylece donup duruyor.

KeepAlive.Start(url) ile cagiriliyor. IsKeepingAlive ile durum kontrol ediliyor. KeepAliveStop ile de islem sonlandiriliyor.

Sitenin linki : http://web.archive.org/web/20100213092317/http://www.rexmorgan.net/journal/fixing_aspnet_ldquokeep

18 Ekim 2013 Cuma

Github - 2

Kaldigimiz yerden... 

Branch 

Branch projenin gidisinde ayri bir kol olusturarak kodun paralel evrenini yaratmaktir diyebilirim. (Fringe yapti beni boyle) 
Neden ? 
Ekip olarak bir ekleme yapacaksiniz ve birbirinizin dosyalarina girme ihtimaliniz var. Kodun orjinal halini korurken bir degisikligi denemek ve sonuclarini gormek istiyorsunuz ama orjinal halinin korunmasini da istiyorsunuz. iste o zaman branch lazim olabiliyor bize.

Orneklere gecelim yine
yenidal diye bir branch yaratarak ise basliyoruz.
git checkout -b yenidal

-b : branch yerine kisa kullanim icin.. bu cumleyi git checkout branch yenidal olarak da yazabilirdik

simdi Code/lib/test2.rb diye bir dosya olusturdum ve icine birseyler yazdim ve commit ettim.

cd lib
subl test2.rb
git add .
git commit -m "test2.rb dosyasini ekledim"
hatta ilk dosyami da degistirip kaydediyor ve commit ile gonderiyorum
subl test1.rb
git add .
git commit -m "test1.rb dosyasini degistirdim"
simdi projede iki tane branch var.
git hist --all
* 807fd32 2013-10-18 | test1.rb dosyasini degistirdim (HEAD, yenidal) [Macrop]
* eb86530 2013-10-18 | test2.rb dosyasini ekledim [Macrop]
* cf5ccc3 2013-10-17 | Amending ext (master) [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (v1) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]
master branch'e gecmek icin asagidaki komutu kullaniyorum
git checkout master
Master dayken readme diye bir dosya olusturdum kaydettim commit ile gonderdim. (su anda master branch'de oldugumuzdan bu commmit de master'a gitti)
subl readme
git add .
git commit -m "readme eklendi"
simdi projenin tarihcesini aldigimizda text formatinda da olsa grafik sekilde projenin iki branch ustunde yurudugu ve en son yapilan commitler gozukuyor. (Satir baslarindaki cizgilere bakin )
git hist --all
* 218bf8c 2013-10-18 | readme eklendi (HEAD, master) [Macrop]
| * 807fd32 2013-10-18 | test1.rb dosyasini degistirdim (yenidal) [Macrop]
| * eb86530 2013-10-18 | test2.rb dosyasini ekledim [Macrop]
|/  
* cf5ccc3 2013-10-17 | Amending ext [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (v1) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]

Merge

olusturulan iki dali tekrar birlestirme islemine de merge deniyor.
Once olusturdugumuz dala (branch) geciyoruz ve merge komutu ile bagliyoruz.

git checkout yenidal
Switched to branch 'yenidal'

git merge master
Merge made by the 'recursive' strategy.
 readme |    1 +
 1 file changed, 1 insertion(+)
 create mode 100644 readme

git hist --all
*   2d06fdb 2013-10-18 | Merge branch 'master' into yenidal (HEAD, yenidal) [Macrop]
|\  
| * 218bf8c 2013-10-18 | readme eklendi (master) [Macrop]
* | 807fd32 2013-10-18 | test1.rb dosyasini degistirdim [Macrop]
* | eb86530 2013-10-18 | test2.rb dosyasini ekledim [Macrop]
|/  
* cf5ccc3 2013-10-17 | Amending ext [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (v1) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]
yine ASCII de olsa grafik formatinda projenin iki dala ayrilip tekrar birlesmesini gorebiliriz.
peki bir cakisma olursa ne olacak ?

Conflict

simdi master'daki readme'yi degistirip kaydediyor ve add - commit ile gonderiyorum
ardindan yenidal'a geciyor ve readme'yi degistirip add - commit ile onu da gonderiyorum

simdi icleri birbirinden farkli ayni isimde iki tane dosya iki ayri branch'da bekliyor.
birlestirmeye kalkinca
 git merge master
error: 'merge' is not possible because you have unmerged files.
hint: Fix them up in the work tree,
hint: and then use 'git add/rm <file>' as
hint: appropriate to mark resolution and make a commit,
hint: or use 'git commit -a'.
fatal: Exiting because of an unresolved conflict.
o halde birlestirelim bunun icin dosyanin icine bakiyoruz

subl readme
soyle birsey var
file for master branch
<<<<<<< HEAD
bunu da yenidal dan degistirdim
=======
Master'dayken degistirdim
>>>>>>> master
cakismanin oldugu yer ve hangi dosyada nasil yer aldigina dair bir bilgi aldik. Simdi bunu elle cozmemiz lazim. yani hangisini dogru kabul edeceksek o bolumu birakiyor digerini siliyoruz

file for master branch
bunu da yenidal dan degistirdim
bu cakisma duzeltildigine gore simdi birlestirmeye devam edebilirim

git add readme
git commit -m "cakisma cozuldu"
Normalde git merge islemi icin grafik tabanli bir arac saglamiyor ancak baskalari ile calisabiliyor. "Meld" benim gordugum ve isini iyi yapan bir arac gibi. Asagidaki gibi kurabilirsiniz
sudo apt-get install meld
sonra git'in global konfigurasyon dosyasi uzerinde yapacaginiz bir degisiklikle conflict cozmek icin artik meld kullanilacagini soyleyebilirsiniz.
 bunun icin subl ~/.gitconfig yazip dosyanin icine sunlari eklemek

~/.gitconfig

[merge]
tool = meld
[diff]
tool = meld
conflict mesaji aldiginizda git mergetool yazarsaniz artik meld acilacak
git mergetool
Merging:
readme

Normal merge conflict for 'readme':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (meld):

oklari kullanarak conflicti cozmek mumkun artik. Daha kolay degil mi ?
sonrasi gene ayni
git add readme
git commit -m "cakisma gene cozuldu"

Rebase 

Merge ile cok benziyor aslinda. Farki commit agacinin (tarihcesinin) farkli olmasi. Rebase yapdiginizda daldaki commit tarihcesine materdaki commit tarihcesi de getiriliyor. boylece master aslinda branch'in commit tarihcesinin bir parcasi oluyor. Okumasi daha kolay bir tarihce olusmasina ragmen acik kaynak kodu gibi cok kullanicinin calistigi durumlarda tarihce bozuldugundan kullanicilarin kafasini karistirabilir. 

Birden cok repository (clone)

Simdiye kadar yaptigim ornekleri gittest diye bir klasorun icinde yaptim. simdi o klasorden bir uste cikiyorum ve asagidaki komutu veriyorum
git clone gittest gittest_clone
klonlanmis repository tarihcesini de tasiyarak gelir. klonladigimiz dizine girip tarihcesini alirsak gittest'teki tarihce ile ayni oldugunu goruyoruz.
git hist --all

Origin

projenin orjinal halini ifade ediyor. (asil ilk merkezi repository)
git remote
origin
git remote show origin

* remote origin
  Fetch URL: /home/aliiybar/Code/gittest
  Push  URL: /home/aliiybar/Code/gittest
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    master
    yeni
  Remote branches:
    master  tracked
    remove  tracked
    yeni    tracked
    yenidal tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

Remote Branch

biraz once olusturdugumuz klon icinde branch'lara baktigimizda bir tek master'i goruyoruz. 

git branch
* master
-a parametresini verdigimizde tamami goruntuleniyor
git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/remove
  remotes/origin/yeni
  remotes/origin/yenidal

Fetch

orjinal repo'daki degisiklik durumunda (once orjinalde bir degisiklik yapalim)
cd ..
cd gittest
subl readme
git add readme
git commit -m "readme degisti"
klona gecip fetch komutunu calistiralim
cd ..
cd gittest_clone
git fetch
git hist --all
....
73076dd 2013-10-18 | master'a readme eklendi (HEAD, origin/master, origin/HEAD, master) [Macrop]
....
fetch komutu commit tarihcesini getirdi ama merge etmiyor. reame dosyasina bakinca degismemis oldugunu goruyorum
merge edebilmek icin su komutu veriyorum
git merge origin/master

Pull

aslinda iki komutun birlesimi diyebiliriz
git fetch 
git merge origin/master 
diyecegimize 
git pull diyoruz o kadar . 

Tracking branch

clone ile aldigimiz repoda yenidal diye bir branch yok ama orjinalde vardi. yenidal'i takip etmek icin tracking branch kullaniyoruz
git branch --track greet origin/greet
git branch -a
git hist --max-count=2

Remote Add

cd gittest_remote
git remote add shared ../hello.git

Push

yapilan degisiklikleri lokal repository'den server'a veya uzak repository'e gondermek icin push kullanilir. 
git push shared master

Lokal repository yayinlamak

once calisilan klasor icinde asagidaki komutu verip bir cesit web server calismasini sagliyoruz
git daemon --verbose --export-all --base-path=
Sonra baska bir terminal penceresi acarak 
git clone git://localhost/hello.git network_hello
cd network_hello
ls


Dip Not : Windows kullanicilari icin satir sonundan dolayi degismis gibi gorunen dosyalar icin
Ø    git config --global core.autocrlf true


Devam edecek ...

17 Ekim 2013 Perşembe

Github - 1

Github'a baslarken

Guncellemeye bugun github ile basliyorum. Bu konuyu tamamen anlamak cok cok onemli.

Yalniz program yazan bir programci ile, ekip ile yazan programci arasinda ciddi bir fark var. Ekip buyukse bu fark da buyuyor.

Github aslinda bir disiplin. Kullandiginiz araclar hem yalniz hem ekip ile yazmaniza imkan veriyor.

Kullanim mantigi diger benzerlerinden oldukca farkli.

Daha once Visual Source Safe ve SVN kullanmistim ama git bambaska birsey.

Once teknik olarak en bariz farktan yola cikalim. github'da server'dan bagimsiz hareket edebilmenizi saglayan bir altyapi var. Yani kodlari yazdiginiz alan, kodlari kendi bilgisayariniz uzerinde arsivlediginiz alan, ve sunucu uzerinde arsivlenen baska bir alandan olusan 3 asamali bir kod saklama mekanizmasi var.

Basitce github uzerinde bir hesap acarak ise basliyorsunuz.  (nasilini anlatarak zaman harcamayalim klasik yontemlerle deyip gecelim)

Hesabi acar acmaz iceridesiniz. Kullanici adi ve Parolaniz her zaman lazim olacak unutmayin

Isterseniz sag ustte isminizin ustune basip "Edit Profile" a basarak kendinize ait detay bilgiler ve fotograf koyabilirsiniz. Yani github aslinda size kodlarinizin arsivlenmesi ve paylasilmasinin otesinde bir de sosyallesme imkani taniyor.

Ubuntu Linux uzerinde bu islemleri gerceklestiriyor olacagim ama windows veya mac ile de ayni sonuclari alacaksiniz cunku hep command prompt'ta olacagiz

Altta kaynaklar kisminda linkini bulabileceginiz gitimmersion sitesinde adim adim ilk asamalarin nasil gecildigi var.

Sifirdan Basliyoruz

Ben sirayla yaptiklarimi ve gerekli yerlerde ne anlama geldigini yazarak ilerleyecegim.

cd Code
mkdir gittest
cd gittest
git init
Code dizinine gecip gittest diye bir klasor yaratip icine girdim. Sonra da git init ile bu klasorun git ile versiyon takibi yapilacagini bildirdim .

subl test1.rb
sublime ile test1.rb diye bir dosya olusturup icine "My First File" yazdim. Kaydedip ciktim

klasordeki dosyalarin durumlarini sorgulamak icin git status komutunu kullaniyorum.
git status

# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# test1.rb
nothing added to commit but untracked files present (use "git add" to track)
git bana test1.rb diye bir dosyanin bulundugunu ama takip edilmedigini soyluyor.

o halde takip edilmesi icin ekleyelim
git add test1.rb
bu sekilde dosya dosya ekleme yapilabildigi gibi "git add ." ile tum klasoru bir kerede ekleyebiliriz
Tekrar git status ile klasore bakiyorum
git status

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
# new file:   test1.rb

Commit

simdi test1.rb adli dosyanin takip edildigi ama yapilan degisikliklerin "commit" ile kaydedilmedigini soyluyor. O halde commit ile degisiklikleri kaydedelim. Bu asamada diger versiyon kontrol sistemlerinden farkli olarak commit bu dosyayi server'a yollamayacaktir. Onun yerine kendi bilgisayariniz uzerindeki bir alana kopyalayacaktir.
git commit
bu komutu verdiginizde git size aciklama yazmaniz icin bir metin dosyasi acacaktir. Her commit sirasinda duzgun yazilmis aciklamalarla sonradan geri donmek kolaylasacaktir.

yazacaklarim bitince Ctrl + X ile bu ekrani kapatiyorum dosya ismini sordugunda enter ile kabul ediyorum

ve islem tamam. Artik ilk commit'im gerceklesti.

simdi text dosyami tekrar acip degisiklik yapip kaydediyorum. Boylece commit ettigim ile arasinda fark olusuyor.
git status ile degisiklikler hakkinda bilgi sahibi olabilirim

tekrar commit yapmak icin tekrar git add . ile eklemek veya git commit -a ile iki islemi birlestirmek zorundayim
git commit -m "degisiklik tanimi"
bu sekilde commit yaptiginizde tek satirlik bir aciklamayi komut satirinda ekleyebilme ve bir sonraki metin editorunun acilmasini engelleme sansina sahibiz. 

Sonra bir tane daha ayni adimdan yapip toplam 3 tane commit olmasini sagladim

Log

Simdi git log ile neler yaptigimi gorebilirim
git log

commit 913f1bff17b96d598ad446470e3128a949b8772e
Author: Macrop <Macrop@yahoo.com>
Date:   Thu Oct 17 13:14:23 2013 +0100

    3rd commit

commit 9c46dcbf6e44a8661e4219078003112084611cd8
Author: Macrop <Macrop@yahoo.com>
Date:   Thu Oct 17 12:05:05 2013 +0100

    My Second Commit

commit 3beabaffd7b3e716eda48111ab19c43bc3b80822
Author: Macrop <Macrop@yahoo.com>
Date:   Thu Oct 17 11:56:40 2013 +0100

    My First commit on test1.rb


bunu daha duzgun gormek icin parametre olarak asagidakini deneyebilirim

git log --pretty=oneline

913f1bff17b96d598ad446470e3128a949b8772e 3rd commit
9c46dcbf6e44a8661e4219078003112084611cd8 My Second Commit
3beabaffd7b3e716eda48111ab19c43bc3b80822 My First commit on test1.rb

git log'un aldigi parametrelere ornekler asagida. Daha fazlasini incelemek icin  man git-log 
denenebilir.
git log --pretty=oneline --max-count=2
git log --pretty=oneline --since='5 minutes ago'
git log --pretty=oneline --until='5 minutes ago'
git log --pretty=oneline --author=<your name>
git log --pretty=oneline --all
 oldukca duzgun gozuken bir log formati icin
git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short

* 913f1bf 2013-10-17 | 3rd commit (HEAD, master) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit [Macrop]

* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]


Configuration


simdi bazi kisaltmalar tanimlamak ve isimi kolaylastirmak icin vi ~/.gitconfig ile configurasyon dosyasini acip icine sunlari yazdim

[user]
name = Macrop
email = Macrop@yahoo.com
[merge]
tool = meld
[diff]
tool = meld
[alias]
  co = checkout
  ci = commit
  st = status
  br = branch
  hist = log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short
  type = cat-file -t
  dump = cat-file -p

Checkout

2. sirada yaptigim commit'e geri donmek istiyorum. git checkout <hash> ile ger donebilirim. hash icin git log ile aldigim listeye bakin.

git checkout 9c46dcb
HEAD is now at 9c46dcb... My Second Commit

dosyanin icine baktigimda tam olarak 2. commitim sirasindaki halini goruyorum.
cat test1.rb
Simdi tekrar son haline donelim
git checkout master
cat test1.rb
evet icerikte ekledigim 3. satir tekrar gozukmeye basladi

Tag

Bu commit'i v1 olarak isaretlemek (tag) istiyorum
git tag v1
onceki bir commiti tag ile isaretlemek icin ya hash ve checkout ile cagiriyorum ya da ozel bir kullanim ile v1'den bir onceki commit demek olan sunu kullaniyor ve oyle cagiriyorum

git checkout v1^
Bir kere tagladiktan sonra tag ile checkout yapabilirim
git checkout v1
git tag
sadece git tag yazarak tum taglarimin listesini alabilirim. Log aldigim zaman da taglari gormem mumkun

Son committen sonraki islemleri geri alma (git add yapilmadiysa - not staged)

committen sonra yapilan degisiklikleri yok saymak icin git checkout test1.rb ile yani dosya ismi ile checkout yapmak yeterli 
git checkout test1.rb

Son committen sonraki islemleri geri alma (git add yapildiysa - staged)

dosyada bir degisiklik yaptiniz sonra git add ile commit icin hazirladiniz ve farkettiniz ki geri alinmasi gereken bir durum var. git status ile baktiginizda aslinda size nasil geri alinacagini soyleyen bir mesaj veriyor. Yani kisaca soyle 
git reset HEAD test1.rb
iste geri dondunuz. Simdi stage area da kalan izi de yok etmek icin 
git checkout test1.rb
tamamen geri donmus olduk.

Commit'i undo ile ger cevirme (revert)

once bir commit ile bir degisiklik yapalim
git add test1.rb
git commit -m "istenmeyen degisiklik"
Simdi bu commiti geri cevirmeye calisalim
git revert HEAD
git hist
* 6483211 2013-10-17 | Revert "istenmeyen degisiklik" (HEAD, master) [Macrop]
* e4de5de 2013-10-17 | istenmeyen degisiklik [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (v1) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]

git hist icin yukaridaki configuration basligina bakin lutfen.
Gordugunuz gibi islem geri alindi ve geri alinma kaydi da ek olarak tarihceye eklendi.

Commit silme

Son islemi oops olarak tagliyorum

git tag oops
simdi reset  komutu ile son daha once v1 olarak tagladigimiz yerden sonraki commitleri siliyoruz
git reset --hard v1
HEAD is now at 913f1bf 3rd commit
git hist
* 913f1bf 2013-10-17 | 3rd commit (HEAD, v1, master) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]
Aslinda silinmediler 
git hist --all
* 6483211 2013-10-17 | Revert "istenmeyen degisiklik" (oops) [Macrop]
* e4de5de 2013-10-17 | istenmeyen degisiklik [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (HEAD, v1, master) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]
--all parametresi ile tekrar gozukur hale geliyorlar

git tag -d oops
Deleted tag 'oops' (was 6483211)

git hist --all
* 913f1bf 2013-10-17 | 3rd commit (HEAD, v1, master) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]
Tagi silince komple silinmis oldu. 

Commit duzeltme

bir commiti yaptiktan sonra icinde duzeltme yapmak da mumkun 
subl test1.rb
git add test1.rb
git commit -m "Amending"
[master 5889e7a] Amending
 1 file changed, 2 insertions(+)

subl test1.rb
git add test1.rb
git commit --amend -m "Amending ext"
[master cf5ccc3] Amending ext
 1 file changed, 3 insertions(+)

git hist
* cf5ccc3 2013-10-17 | Amending ext (HEAD, master) [Macrop]
* 913f1bf 2013-10-17 | 3rd commit (v1) [Macrop]
* 9c46dcb 2013-10-17 | My Second Commit (v0) [Macrop]
* 3beabaf 2013-10-17 | My First commit on test1.rb [Macrop]

once text dosyasina bir seyler yazdim ve commit yaptim
sonra birseyler daha yazdim ve tekrar commit ederken --amend parametresini kullandim.

Dosya tasima

git tarafindan takip edilen bir klasorde tasima islemini su sekilde gerceklestiriyoruz

mkdir lib
git mv test1.rb lib
ls
lib
git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# renamed:    test1.rb -> lib/test1.rb

normal mv komutu yerine git komutu kullanmama dikkat edelim. Bolye yaparak aslinda asagidaki gibi yazsam da yapilacak olan islemi bir kac adim kisaltmis oluyorum

mkdir lib
mv hello.rb lib
git add lib/hello.rb
git rm hello.rb

.git dizini


ls -C .git
branches  COMMIT_EDITMSG  config  description  HEAD  hooks  index  info  logs  objects ORIG_HEAD  refs

cat .git/config

Son commit

Son yapilan commit i bulmak icin
git hist --max-count=1


git cat-file -t <hash>

git cat-file -p <hash>

Kullanici Degistirme

global olarak git kullanici adi ve emailini girmek icin
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

lokal olarak bir dizinin baska bir kullanici ile iliskilenmesi icin
git config user.name "Your Name"
git config user.email "you@example.com"


Simdilik burada kaydediyorum ama branch kavramindan baslayarak devam edecegim




Kaynaklar 

http://www.github.com
http://gitimmersion.com

16 Ekim 2013 Çarşamba

Gelisim

Baslarken

Bugune kadar bircok mecrada, bircok konuda yazdim ama artik herseyi biraraya toplamanin zamani geldi. Umarim herseyi toplarken herkesi de toplarim.

Yillardir gelisen teknoloji ve yenilikleri takip etmenin onemini soyler dururum. Bugun geldigim nokta beni hakli cikarirken eksikliklerimi de yuzume vurdu. Projelere gomulmek, kendi kendine okumak, ogrenmek ile o kadar zaman harcadim ki, bugun yenilikleri takip ederken neleri kacirdigimi gormek ve aslinda benim takibimin cok kucuk bir oran oldugunun farkina varmak beni cok uzdu.

Bunu blogda mi yapmaliyim yoksa web sitesi haline mi getirmeliyim arada kaldim. Web sitesi yaparsam biliyorum ki uzun sure sonra hala kendimi baslamamis olarak bulacagim.

O yuzden en guzeli blog ile baslamak dedim kendi kendime

Nereden Nereye

Ilk commoder 64'un eve girdigi gunden beri program yaziyorum.

10 print "Ali"
20 goto 10

Bu ilk yazdigim koddan bu yana yazmadigim proje kalmadi gibi birsey.

Sirayla
dBase
Clipper (ki cok sevdigim bir dildi)
c (lazim olursa diye syntax i ogrenmekte fayda var)
Informix r4gl (Unix programciliginda ilk asamalarimdi)
Visual Objects (evet ya oyle bir dil vardi)
Visual Fox Pro  (clipper'a benziyor diye visual programlamada asama olarak kullanmistim)
Visual Basic 4-5-6 (cok havaliydik o zamanlar)
HTML (internette olamamayi kaldiramamisti bunyemiz)
ASP (madem internette variz programlayalim bari)
Javascript (bunsuz olmuyor diyorlardi)
CSS (e guzel birsey.. hem de kolay)
ASP.NET (yerimizde saymayalim teknolojiyi takip edelim adamlar cok degistirmis isi)
Ajax - JQuery (Bildigimiz seylerdi zaten baglayiverdik birbirine bitti gitti)
VB.NET (temel yapiyi ogrendik bunu windows ortamina da aktarsak)
C#.NET (kutuphaneler ayni zaten alt tarafi syntax farkli)

derken ...

Ruby (ZINK)

eee hani kolayca geciyorduk dilden dile ne oldu simdi

Birdenbire hersey kokten degisti. Daha dogrusu biz projelerle bogusurken dunyanin nereye geldigiyle yuzlestim.

Zaman icinde oyle veya boyle kullandigim birseylere benzemesini bekledigim hicbirsey neredeyse artik benzemiyor.

Ruby ogrenme macerami diger blog'umda yaziyorum oradan da takip edebilirsiniz (http://rubyogreniyorum.blogspot.co.uk/)

Anlatmak istedigim biz birseylere kendimizi kaptirmis giderken dunyada birseyler gelisiyor ve kendimizi nasil guncel tutacagimizi bazen goremiyoruz. Kendimizi guncel tuttugumuzu sanarken aslinda at gozlugu ile konuya baktigimizi sonradan farkediyoruz. Iste bu rahatsiz edici.

Yillardir kendimi en son teknolojilere adapte etmeye calisirken birden cok gerilerde kaldigimi gordum. 2 hafta oncesine kadar ben kendimi cok guncel saniyordum.

Sorun aslinda kendimi guncellemek de degil. Kendimi guncel tutma algoritmamda hata oldugunu gormek ve guncelleme algoritmasini guncellemek.

Hala buna bir cikis noktasi ariyorum. Herkesin katkisini da bekliyorum. Kollektif akil her zaman en iyisidir.