Django'da Uygulama Oluşturma

Django, geliştiricilere projeyi parçalara ayırması konusunda önerilerde bulunmaktadır. Bunun içinse gerekli araçları gerliştiriciye sağlamaktadır. Django'da bu sebeple uygulama kavramı vardır. Örneğin bir websitesi düşünün. Bu websitesi hem forum içerecek hem de blog bölümü içerecek. Ancak bunları tek bir klasör içinde yazmamız pek kolay değil. Django buna çözüm olarak bu bölümlerin her birini bir uygulama olarak el almamızı istiyor. Yani forum ayrı bir uygulama olarak oluşturulacak ve projeye bağlanacak, aynı durum blog için de geçerli.

Örneğin, ben bir blog oluşturmak istiyorum. Bu blog için bir uygulama oluşturmam gerek proje içinde: 
$\ilksite> django-admin startapp blog
Bu işlemden sonra görüleceği üzere blog adında bir uygulama oluşturulmuş oldu.
  • ilksite/
    • blog/
      • __init__.py
      • admin.py
      • apps.py
      • models.py
      • tests.py
      • views.py
    • ilksite/
      • ...
    • db.sqlite3
    • manage.py
Şimdi sırasıyla uygulama içindeki dosyaları inceleyelim.
  • admin.py: Bu dosya uygulama ile admin paneli arasında gerçekleşecek olan ilişkileri barındıracak. Örnek olara oluşturduğumuz bir modeli admin panelinde tanıtmak istiyorsak bu dosya üzerinden kaydetmemiz gerekecek.
  • apps.py: Uygulamanın ayarlarını barındıran kısımdır. Uygulamamızı projeye tanıtırken bu dosyaya ihtiyacımız var.
  • models.py: Uygulamaya ait modelleri barındıran dosyadır.
  • tests.py: Uygulamanın çalışma durumunu test edeceğimiz dosyadır. Herhangi bir güncelleme sonrası önceden düzgin çalışan fonksiyonlarda herhangi bir sıkıntı olursa bu sayede tespit etmiş olacağız. Bu sadece Django'ya özel olan bir durum değil. Her yazılım, geliştirme esnasında teste tabi tutulmalıdır.
  • views.py: Uygulamamıza ait view yapılarını içerecek dosyadır.
Örneği başarılı bir şekilde oluşturduk ancak daha işimiz bitmedi. Bu uygulamayı projeye yüklememiz gerekiyor. Bunun için settings.py dosyası açılır ve INSTALLED_APPS list yapısına uygulama eklenir:
...

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',
]

...
Ekleme yapıldıktan sonra örnek bir view function yazalım. Bunun için uygulama klasöründeki views.py açılır:
from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.

def index(request):
    return HttpResponse("Merhaba!")
Bu işlemden sonra urls.py adında yeni bir dosya uygulama klasörü içinde oluşturulur:
from django.urls import path

from blog.views import index

urlpatterns = [
    path("", index, name="index"),
]
Sonrasında bu urlpatterns proje klasöründe yer alan ana urls.py dosyasında tanıtılır:
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
]
Şimdi projeyi çalıştırmayı deneyelim ve 127.0.0.1:8000 adresini açalım ve view üzerinden ilk HttpResponse nesnemizi başarıyla döndürdük:
Django HttpResponse

Kaynaklar


Devamını Oku »

Django'da Proje Oluşturma

Django, Python bazlı bir Web Framwork'tur.  Mimari olarak ORM'dir ve MVT desenini kullanmaktadır. ORM'in açılımı Oriented-relational mapping'dir. Peki ORM'in anlamı nedir? ORM mimarisine sahip framework'larda programcının SQL kod ile database table yazmasına gerek yoktur. Bunun yerine veritabanı tabloları Pyhton ile model dediğimiz sınıfsal yapılarla oldukça basit bir şekilde oluşturulabilmektedir. Peki MVT nedir? MVT'nin açılımı Model-View-Template'dir. Model kısmında söylediğimiz gibi database için gerekli table yani tablolarımızı oluşturuyoruz. View kısmında ise Model ile Template arasındaki ilişkiye köprü olan mantıksal yapıyı kullanmaktayız. Template kısmı ise direkt olarak kullanıcıya web browser üzerinden sunulacak olan bölümdür. Template yapıları aslında oluşturacağımı html dosyalarıdır. 

Projeyi oluşturmadan önce Django'yu indirmediyseniz, resmi web sitesinden indirmelisiniz. Sonrasında işletim sisteminize uygun olarak güncel sürümü önerilen şekilde yüklemelisiniz. Eğer Windows işletim sistemi kullanıyorsanız pip package manager üzerinden indirme gerçekleştirmeniz gerekmektedir. 

Kurulumları yaptıktan sonra artık Django projesini oluşturmaya başlayabiliriz. Öncelikle projemin kaydolmasını istediğim yerde command prompt yani cmd'yi açıyorum. Aşağıdaki komutu girerek ilk django projemi oluşturuyorum:

$> django-admin startproject ilksite
İlksite adındaki projemi başarıyla oluşturdum. Şimdi sırasıyla ilk olarak ilksite klasörüne cd ile giriş yapıyorum sonrasında ise code . komutu ile Visual Studio Code ile projemi açıyorum:
$> cd ilksite
$\ilksite> code .
Şimdi proje klasörü içinde gelen dosyalarımızı inceleyelim:
  • ilksite/
    • ilksite/
      • __init__.py
      • asgi.py
      • settings.py
      • urls.py
      • wsgi.py
    • manage.py
Burada bizi ilgilendiren üç kısım dosya var. Bunlar:
  • settings.py: Proje için gerekli ayarları bu dosya üzerinden gerçekleştiriyoruz.
  • urls.py: URL yönlendirmelerinin yönetildiği ana dosyadır.
  • manage.py: Projeyi yönetme kısmı bu dosya üzerindendir. En basit olarak projeyi çalıştırma, veritabanını güncelleştirme gibi tüm eylemleri bu dosya aracılığıyla yapmaktayız.
Diğer dosyalar, özelli asgi.py ve wsgi bizim neredeyse hiç dokunmayacağımız kısımlardır. Bu dosyalar web sunucular ile web framework arasındaki ilişkiyi sağlamakla yükümlü dosyalardır. Proje şu anda basit anlamda wsgi kullanmaktadır. asgi.py ise asenkron web uygulamaları için kullanılmaktadır. Söylediğim gibi bu dosyalarla şimdilik bir işimiz yok. Ancak deployment esnasında işimiz düşecektir.

Artık projemizi aşağıdaki komut ile çalıştırabiliriz:
$\ilksite> python manage.py runserver
Projemiz local sunucu üzerinde canlıya alındı, test etmek için belirtilen adrese tarayıcınız üzerinden gidin (http://127.0.0.1:8000/)
Django İlk Proje

Bu görüntüyü aldıysak işlemleri başarılı bir şekilde gerçekleştirmişiz demektir. Diğer yazıda görüşmek üzere.

Kaynaklar:

Devamını Oku »

C# Interface Nedir?

Interface kullanımı sınıflarla benzerlik gösteren ama bir sınıf gibi davranmayan hatta bir sınıf olmayan yapılardır. Interface'i arayüz yani şablon olarak düşünebiliriz. Peki Interface olayı nedir, neden böyle bir şeye ihtiyaç duyulmuş?

Interface'ler öncelikle kod üzerinde soyutlama yapmamızı sağlar. Şimdi diyebilirsiniz ki soyutlama yani abstraction nedir? En basit şekilde soyutlamayı açıklamam gerekirse, bir bilgisayar düşünün, bir kişi bu bilgisayarı sadece power tuşuna basarak çalıştırabilir. Ancak onun arkasında ne gibi olaylar oluyor hiçbir fikri yok zaten olmasına da gerek yok bir kullanıcı olarak. Onun yapması gereken tek şey sadece o power tuşuna basmaktır. İşte soyutlama da böyle bir şey bir anlamda olayı olabildiğince basitleştirme ve arkaplanda dönen işleri saklamak diyebiliriz.

Interface'lerin bir diğer varolma sebebi ise sınıflardaki miras işleminin sınırlı olması. Bir sınıf sadece bir tane sınıftan miras yani kalıtım alabiliyor. Başka bir sınıftan daha kalıtım alma imkanı yok. Ancak bir sınıfa birden fazla sayıda interface implement edilebilir. Burası önemli çünkü Interface'lerden kalıtım alınmaz yani inherit edilmezler, implement edilirler.

C#'ta interface'in avantajlarını şöyle sıralayabiliriz:
  • Interface sayesinde kod içerisinde plug-and-play yani tak ve çalıştır yöntemi etkinleştirilmiş olur. Şöyle düşünelim iki tane sınıfımız olsun firstClass ve secondClass diye. Bu sınıflara bir tane IFoo adında bir interface implement edilmiş. Sonrasında bu bir tane system olarak çalışacak bir sınıfımız olsun. Ona da FooSystem sınıf diyelim. Bu sistem sınıfında nesneleri yöneteceğiz. FooSystem sınıfında run adında bir fonksiyonumuz ve bu fonksiyon IFoo tipinde parametre alsın. firstClass ile üretilmiş nesneyi de, secondClass ile üretilmiş nesneyi de bu run methoduna gönderebiliriz. Çünkü Interface bir referans tiptir. Bir interface implement edildiği tüm sınıflardan üretilen nesnelerin referanslarını alabilir. Yani her iki farklı tipteki nesneyi run metodunda kullanabiliriz. Eğer sonrasında farklı bir nesne kullanımı gerekirse o nesnenin (thirdClass)sınıfına Interface implement edilip sonrasında nesnenin kendisi  run metoduna rahatlıkla gönderilebilir. Zaten buradaki plug-and-play olayın kasıt budur. Tekrar o sınıf tipi için ekstra bir metot yazmamıza gerek yok FooSystem sınıfına.
  • Kod içerisinde büyük oranda soyutlama sağlanır.
  • Loose Coupling kullanımı sağlanmış olur. Bu kavramı bir sistemin parçalarının birbirinden olabildiğince bağımsız olacak şekilde çalışması olarak açıklayabiliriz. Bir parçanın çalışmaması veya düzgün çalışmadığı halde diğer parçanın doğru şekilde çalışmasına engel olmaması loose coupling olarak açıklanabilir. Wikipedia sayfasından bu kavram hakkında daha çok bilgi edinebiliriz. 
  • Kod içerisindeki karmaşıklığı önemli derecede azaltmaktadır ve kod okunabilirliği açısından oldukça işlevseldir.
  • Yukarıda belirttiğimiz gibi bir sınıfın çoklu kalıtım alabilmesine bir bakımdan imkan vermektedir, tabi implement olarak.
Interface'de sadece metot ve property bildiriminde bulunuruz. Yani bunların sadece signature olarak interface içerisinde bildirebiliriz. Bunlar bizim soyut olarak metot veya property bildirimlerimizdir. Implement edildiği sınıf içinde mutlaka bu bildirimlerin gövde kodu yazılmalıdır. Ayrıca interface içinde tanımladığımız signature yani imzalar access modifiers yani erişim belirteçleri kullanılarak bildirilmezler. Direkt olarak int topla(); veya void say(); gibi yazılır. Zaten default olarak bu bildirimlerin erişim belirteci public'tir. Bir diğer bilinmesi gereken önemli husus ise interface'lerden nesne üretilemeyeceğidir. Kısacası interface'ler bir sınıf olmadığı için kendilerinden nesne üretilemez.

Genelde interface tanımlanırken interface isminin ilk harfi I olacak şekilde yazılır. Bu genel kabul görmüş bir kullanımdır. Kod okurken onun bir interface olduğunu anlamamızı sağlar. (Örnek: IDeneme)
Devamını Oku »

C# Değer Tip ve Referans Tip (Value Type - Reference Type)

Programcı olarak bilmemiz gereken kavramlardan olan değer tip ve referans tip nedir, onlardan kısaca bahsedeceğiz. 

Öncelikle eğer bilmiyorsanız, programlama yaparken kod kullandığımız yapılar ve veriler, stack ve heap adında iki tane hafıza bölgesinde depolanmaktadır. Stack hafıza bölgesi isminden anlaşılacağı üzere aslında stack veri yapısının çalıştığı gibi çalışan bir çeşit hafıza kullanımı sağlayan hafıza bölgesidir. Stack hafıza kullanımında her şey bellidir diyebiliriz, belirli bir adres kullanımı vardır. Stack üzerinde depolanan verilerin hafızanın neresinde konuşlanacağını az çok bilebiliriz. Örneğin main fonksiyonumuz stack üzerinde yer alan ilk frame'dir. Bu frame'leri çerçeve olarak düşünelim. Her fonksiyon çalışmasında bu çalışma sonucu kadar bir fonksiyon çerçevesi stack hafızasına eklenecektir. Zaten stack overflow gibi oldukça popüler kavram da buradan gelmektedir. Sonsuz bir recursive fonksiyon kullanımına olanak verirsek sonuç olarak stack overflow'a izin vermiş olacağız yani stack taşması. Çünkü stack hafıza kullanımımız sınırlıdır. Stack hafızası LIFO açılımı Last-in, First-out mantığına göre çalışır yani son giren, ilk çıkar ya da ilk giren, son çıkar olarak da tarif edebiliriz. int, double, float, decimal gibi standart veri tipleri tanımlanmış değişkenler ve değerler value type(değer tip) olarak görülür ve stack bölgesinde yer alırlar.

Referans tip tanımlamalarda değerler stack yerine heap bölgesinde yer alınmaktadır. Depolanmak üzere yer ayrılacak olan bu değer veya değerler bütününe göre uygun şekilde bir boş hafıza bölümü bulunur ve o noktanın başlangıcını gösteren adres değişken içinde saklanır. Bu adres stack bölümünde depolanmaktadır. ve heap bölgesindeki değer veya değerlerin başlangıç noktasıdır. Yani heap'te yer alan o verilere ulaşabilmemizin tek yolu o adrestir veyahut buna referans da diyebiliriz.

Peki neden böyle bir şeye gerek var? Öncelikle stack bölümünde işlemler daha az maliyetle oluyor, bu noktada heap'e göre çok daha avantajlı fakat dezavantajı sabit yani değişmez olması. Örneğin sabit bir dizi yapısına run-time anında müdahale etmemiz mümkün değil. Program sonlanana kadar ne eleman silebilir ne de eleman arttırımında bulunabiliriz. Ancak dinamik bellek kullanımında yani heap kullanımında böyle bir dert yoktur, dizi içinde sonrasında değişiklik yapabiliriz. Yine aynı şekilde class yapıları, interface, diğer veri yapıları ve dahası için de bu durum geçerlidir. Yani bunlar referans tiplerdir. Ancak heap kullanımı stack bölgesine nazaran daha riskli ve maliyetlidir. Çünkü her program çalışmasında heap kullanımı farklılık gösterecektir ve hafızada nereyi kullanabilirse orayı kullanacaktır. Riskli olmasının sebebi ise hafızada alınan yerin iade edilmemesinden doğacak sonuçlardır. Bilinen en büyük sorunlardan birisi memory leak'e sebep olabilir. Bu nedenle ne kadar yer ayrıldıysa, o kısımla işimiz bittiği anda o kısmı hafızaya geri iade etmeliyiz. Normalde bu iade işlemleri C ve C++ gibi programlama dillerinde elle yapılıyor ancak C#, Java gibi dillerde Garbage Collector denen çöp toplayıcı bu işlemi programcının yerine yapmaktadır, tabi run-time olarak, o sebeple bu gibi riskler C# için son derece düşük sayılabilir ama elbette istisna durumlar vardır.

Devamını Oku »

Visual Studio Code ile C# Geliştirme

Öncelikle belirtmek isterim, şu anda C# programlama ile Visual Studio Community ile yapılabilen her uygulamayı, projeyi VS Code'da oluşturmanız pek mümkün olmayabilir mesela Windows Form projesi yapmanız şu nokta imkansız. Ancak yine de konsol uygulamaları açısından C# programlamayı Visual Studio Code'da yapabilirsiniz.

İlk olarak VS Code'da extensions sekmesinden C# eklentisini yüklemelisiniz.  Bu eklentiyi Visual Studio Code'un Extensions: Marketplace bölümünden isimlerini yazarak bulabilir ve kurabilirsiniz.

Visual Studio Code ile geliştirme yapacağımız için windows terminal(cmd) ile çok işimiz olacak. Çünkü dotnet kullanımını cmd üzerinden yapacağız. O yüzden elimizin altında şu kaynağın olması önemli: https://docs.microsoft.com/en-us/dotnet/core/tools/  

Artık VS Code'u açalım ve yeni bir klasör içinde projemizi oluşturmaya başlayalım. Öncelikle solution oluşturmamız gerek. Oluşturduğumuz proje klasörü içinde cmd açıyoruz. VS Code üzerinden klasör alanına sağ klik yapıp, Open in Integrated Terminal de diyebilirsiniz. Solution'u aşağıdaki komut satırında olduğu gibi oluşturuyoruz:
dotnet new sln -n "helloWorld"
Bu işlemden sonra aşağıdaki resimde görüleceği gibi "The template "Solution File" was created successfully." cevabını alıyoruz. Proje dizinine bakılırsa helloWorld.sln adında bir solution oluştuğu görülecektir.
VS Code C# Geliştirme
Şimdi sıra Console uygulaması oluşturmaya geldi. Nasıl Visual Studio kullanırken özellikle Console Application olarak seçim yapıyorsak burada da ona özel komut satırını girmek zorundayız:
dotnet new console -n "helloWorld"
Bu komut satırından sonra proje dosyalarımız başarılı bir şekilde oluşturulmuş olacaktır. Aşağıda olması gerektiği gibi:
Visual Studio Code C# Console
Peki projemize kendi C# kütüphanlerimizi yazmak istersek ne olacak? Bunun içinde ayrıca bir komut parametresi bulunmakta:
dotnet new classlib -n "Utils"
Utils adında bir C# kütüphanesi oluşturduk. Buraya kadar her şey güzel gittiyse artık bu oluşturduğumuz iki proje dosyasını solution'a eklemeliyiz. Çünkü solution'un şu ana kadar bu projeler hakkında herhangi bir bilgisi yoktu. Yine bu bildirimleri de cmd üzerinden yapıyoruz:
dotnet sln helloWorld.sln add ./helloWorld/helloWorld.csproj
İlk olarak console projemizi ekledik, komut sonrasında "Project `helloWorld\helloWorld.csproj` added to the solution." geribildirimi almamız gerekiyor. Şimdi sıra diğer projemiz olan kütüphaneyi eklememiz gerekiyor:
dotnet sln helloWorld.sln add ./Utils/Utils.csproj
Artık kütüphanemizi, asıl uygulamamıza referans olarak eklememiz gerekiyor:
dotnet add helloWorld/helloWorld.csproj reference Utils/Utils.csproj
İşlem başarılı olduysa şu şekilde bir geri bildirim alırız "Reference `..\Utils\Utils.csproj` added to the project.". Bu işlemden hemen sonra asıl projemizin olduğu dizine gidelim:
cd helloWorld
Sonrasında projeyi ayrı olarak Visual Studio Code ile bu dizinde açalım:
code .
Sonrasında sağ alt kısımda "Required assets to build and debug are missing from 'helloWorld'. Add them?" şeklinde bir kutucuk çıkacak. Bu kutucuktaki yes butonuna tıklayınız. Bu işlemden sonra proje dizininde .vscode şeklinde bir klasör oluşacak ve içinde launch.json ve tasks.json adında iki tane dosya bulunacak. Şimdi tekrar solution'un bulunduğu dizine gidelim cmd ile ve sonrasında code . ile VS Code'u tekrar açalım. Yine aynı şekilde sağ alt kısımda "Required assets to build and debug are missing from 'helloWorld'. Add them?" şeklinde bir kutucuk çıkacak, yes butonuna tıklayın. Yine aynı şekilde o dizinde de .vscode klasörü oluşturulmuş olacak. Bu işlemler debug yapmak için önemli. 

Şimdi projemizi çalıştırmaya çalışalım. Öncelikle Utils klasöründeki Class1.cs adındaki C# dosyama girip test amaçlı bir kütühane metotu yazıyorum:
using System;

namespace Utils
{
    public class Class1
    {
        public void WriteIt(string thing){
            Console.WriteLine(thing);
        }
    }
}
Sonrasında bu kütüphaneyi kullanmak için console proje klasöründeki Program.cs dosyasında aşağıdaki kod yazılır:
using System;
using Utils;

namespace helloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Utils.Class1 deneme = new Utils.Class1();
            deneme.WriteIt("merhaba");
            Console.WriteLine("Hello World!");
        }
    }
}
Sonrasında terminalden console proje dizinine girilir ve aşağıdaki komut satırı ile çalıştırılır:
$(command)> cd helloWorld
$(command)> dotnet run
merhaba
Hello World!
Peki debug yapmak istersek ne yapmamız lazım? Bu durumda yapılması gereken sadece gereken satıra breakpoint koyup f5 tuşuna basmamız yeterlidir. Zaten gerekli ayarlar yukarıda bahsettiğimiz .vscode klasörlerinde mevcut.
Devamını Oku »

C# Miras Alma (Inheritance)

Nesneye Dayalı Programlama'nın en önemli konseptlerinden biri olan inheritance yani miras almadan bahsedeceğiz. Şimdi bu kavramı bir örnekle açıklamaya çalışalım, ElektronikCihaz adında bir sınıfımız olsun. Bu elektronik cihazların ortak özellikleri arasında marka, çalışma durumu, vs. vardır. Örneğin bir bilgisayarın markası varsa aynı şekilde filtre kahve makinesinin de markası vardır. Bunları ayrı ayrı iki sınıf içinde üye olarak tanımlamak yerine tek bir ana sınıfta bu ortak üyeleri bulundurabilir ve o ana sınıftan miras alabiliriz:
class ElektronikCihaz 
{
	public string marka;
	public bool calisiyorMu;
}

class Bilgisayar : ElektronikCihaz
{
	Bilgisayar(string markaAdi, bool calismaDurumu)
	{
		marka = markaAdi;
		calisiyorMu = calismaDurumu;
	}
}


class FiltreKahveMakinesi : ElektronikCihaz
{
	FiltreKahveMakinesi(string markaAdi, bool calismaDurumu)
	{
		marka = markaAdi;
		calisiyorMu = calismaDurumu;
	}
}
Bu şekilde kullanımda bulunabiliriz. Ancak access modifiers konusunda dikkat etmemiz gereken bazı durumlar var. public ve protected olarak tanımlanmış sınıf üyeleri türetilmiş sınıf içerisinde kullanılabilirken, private olarak tanımlanmış üyeler direkt olarak türetilmiş sınıfta kullanılamazlar. Lafın kısası bu şekilde property'lere, üyelere kalıtım yolu ile ulaşabiliriz. Yani buradaki amaç yeniden kullanılabilirliği arttırmak ve kod okunabilirliğini sağlamak diyebiliriz.
Devamını Oku »

C# Static Nedir? Nasıl Kullanılır?

Programlamada static kavramı nedir ve nasıl kullanılmalıdır gibi sorulara cevap verebilmek önemlidir. Öncelikle static kelimesini programlama alanında duyduğumuzda aklımıza doğrudan "sadece bir tane olan, değişmeyen, sabit" gibi çağrışımlar gelmelidir.

Örneğin, bir sınıfta static olarak tanımlanmış bir metota hiç bir zaman o sınıftan oluşturulan nesne üzerinden ulaşmamız mümkün değildir. Bu static metota ancak sınıfın kendisi üzerinden ulaşabilir ve kullanabiliriz. 

Aynı şekilde static olarak bir tanımlanmış bir sınıftan nesne üretemeyiz. O sınıfı sadece içindeki metotlara doğrudan kendisi üzerinden erişebilir ve kullanabiliriz. Örneğin:


static class Ekran
{	
	public static void yaz(string yazi)
	{
		Console.WriteLine(yazi);
	}
}
					
public class Program
{
	public static void Main()
	{
		Ekran.yaz("merhaba dünya");
	}
}
static olarak tanımlanmış bir sınıftan yanda olduğu gibi Ekran ekran1 = new Ekran() şeklinde nesne üretemeyiz, çünkü sınıf static bir sınıftır. Aynı zamanda bu static sınıf içinde tanımlanan metot aynı şekilde static olarak tanımlanmalıdır. Zaten o static olarak tanımlanmazsa şu şekilde hata alınacaktır: cannot declare instance members in a static class.

Bir diğer bilinmesi gereken husus ise const tanımlı değişkenler. Bu şekilde tanımlı değişkenler adının tersine sabit değerli değişkenlerdir ve değişmezler. Yani const tanımlı olan değişken static olarak belirtilmese bile default yani varsayılan olarak static tanımlıdır. Kısacası const değişkenler aynı zamanda static olmaktadır.

Sıra static constructor'a geldi. Static kurucular sadece bir kez çalıştırılır, sınıfta sadece bir static constructor olabilir, ayrıca parametre almazlar, ayrıca erişim belirteçleri ile birlikte tanımlanamazlar aksi takdirde: access modifiers are not allowed on static constructors şeklinde hata verecektir. Sınıf içinde çalışan ilk metot her zaman kendisidir. Kullanım sebebi ise anladığım kadarıyla static sınıf üyelerini en başta başlatmak. Bunu public constructor içerisinde de yapabiliriz ancak o zaman her nesne oluşturmada mecburen static üyelere de tekrar tekrar set metotu uygulanmış olacak. Bir sınıfta static constructor ile beraber aynı zamanda public constructor da tanımlayabiliriz.
using System;

class Uye
{	
	public static int UyeSayisi {get; set;}
	public string ad;
	public int yas;
	
	static Uye() 
	{
		Console.WriteLine("static constructor çalıştı");
		UyeSayisi = 0;
	}
	
	public Uye(string adi, int yasi)
	{
		Console.WriteLine("public constructor çalıştı");
		UyeSayisi++;
		ad = adi;
		yas = yasi;
	}
}
					
public class Program
{
	public static void Main()
	{
		Uye u1 = new Uye("Ahmet", 45);
		Uye u2 = new Uye("Mehmet", 34);
		Uye u3 = new Uye("Ali", 67);
		
		Console.WriteLine(Uye.UyeSayisi);
	}
}
Yukarıdaki kodu iyice inceleyin. Programı çalıştırdığımızda çıktı olarak aşağıdaki sonuçları elde ederiz:
static constructor çalıştı
public constructor çalıştı
public constructor çalıştı
public constructor çalıştı
3
static constructor bir kez çalıştığı görülecektir. Aynı zamanda static olarak tanımlanmış sınıf üyesi birden fazla nesne oluşumuna bağlı şekilde sıfırlanmamaktadır, hatta bu sayede kaç tane nesne oluşturulmuş, gerekli miktarı içinde depolayabiliriz.
Devamını Oku »

C# Get ve Set Metotları (Properties)

Bu yazıda properties kavramın bahsedilecektir. Öncelikle OOP'un barındığı bazı konseptler vardır. Bunlar:

  • Inheritance (Miras alma/Kalıtım alma)
  • Encapsulation (Kapsülleme)
  • Polymorphism (Çok biçimlilik)
Bu yazıda bizi ilgilendiren kavram daha çok Encapsulation yani kapsülleme kavramıdır. Bu kavramı kısaca açıklamak gerekirse, bir sınıftan üretilen nesneye ait metot, değişkenlerin dışarıdan ulaşılmasını engellemektir. Kapsülleme işleminde access modifiers yani erişim belirteçleri kullanılmaktadır. Bir nesneye ait değişkene dışarıdan ulaşılmasını engellemek için private denen erişim belirteci kullanılır. private olarak tanımlanan field'a yani alana(sınıf değişkeni) sadece o sınıf içerisinde erişebiliriz.
class Varlik
{
	private string ad;
}
Ancak bazı durumlarda bu değişkenlere erişmemiz gerekebilir. Normalde ad değişkenine private yerine public olarak erişim izni verilseydi, dışarıdan ulaşabilir ve üstünde hem okuma yapabilir hem de değişiklik yapabilirdim. Fakat bunun yerine C# çok daha kontrollü bir işlem olan properties'i bize sunuyor. Eğer ad alan değişkeninin içeriğini ekrana yazdırmak istersek ama bu değişkende bir değişiklik yapılmasını istemiyorsak bunun için en doğru seçim properties olacaktır. Properties bize iki seçenek sunmaktadır, bunlar get ve set metotlarıdır:
class Varlik
{
	private string ad;
	
	public string Ad
	{
		get { return ad; }
	}
}
Dikkat edilirse yukarıda sadece get metotu tanımlandı ve private tanımlı alan değişkeni döndürüldü. Bu şekilde sadece read-only olması sağlanmış oldu.
public class Program
{
	public static void Main()
	{
		Varlik varlik = new Varlik();
		Console.WriteLine(varlik.Ad);
	}
}
Ekran çıktısı olara "isim yok" başarılı bir şekilde elde edilir. Ancak bu döndürülen değişkene atama yapmak istersek:
public class Program
{
	public static void Main()
	{
		Varlik varlik = new Varlik();
		varlik.Ad = "Ahmet";
	}
}
Şu şekilde hata alırız: Compilation error (line 18, col 3): Property or indexer 'Varlik.Ad' cannot be assigned to -- it is read only

Çünkü Ad property sadece okunabilir olarak çalışmaktadır. Property üzerinden değişiklik yapma iznimiz bulunmamaktadır. Eğer değişiklik yapmak istiyorsak set metodu kullanılmalıdır:
class Varlik
{
	private string ad = "isim yok";
	
	public string Ad
	{
		get { return ad; }
		set { ad = value; }
	}
}
value diye bir atamak yaptık. Buradaki value ifadesi aslında C#'a ait bir keyword. Kısacası atama yaptığımız değerin temsili hali olarak açıklayabiliriz. Eğer şimdi yaparsak şu şekilde:
{
	public static void Main()
	{
		Varlik varlik = new Varlik();
		Console.WriteLine(varlik.Ad);	// çıktı: isim yok
		varlik.Ad = "Ahmet";
		Console.WriteLine(varlik.Ad);	// çıktı: Ahmet
	}
}
Herhangi bir hata almayacağız çünkü o property için hem okuma hem de yazma iznimiz vardır.

Not: Farkettiyseniz property Ad olarak tanımlandı. Yani private olan alan değişkenimizin ismi ile aynı ama tek farkı ilk harfin büyük olması. Bu tarz kullanım genel olarak kabul görmüş bir kullanım tipidir. Bu tarz kullanım kod üzerinde okunabilirliğin artmasına olanak sağlar.

Şimdi biraz daha ileri gidelim. Örneğin, programımızda ülke vatandaşlarının kimlik numaralarını int olarak 9 haneden oluşacak şekilde saklıyoruz. Bu kimlik numarası, kimlikNo adında bir private alan değişkeninde saklanmaktadır. Biz bu değişkene değer atamayı property kullanarak gerçekleştireceğiz. Bu durumda kimlik numaranın en başta geçerli olup olmadığını kontrol edip, o şekilde atama işlemini yapmalıyız. Kimlik numarası 0 dan büyük yani pozitif olmalı hem de tam olarak dokuz haneden oluşmalı, ne eksik ne de fazla:

class Vatandas
{
	private int kimlikNo;
	
	public int KimlikNo
	{
		get { return kimlikNo; }
		set 
		{
			int haneSayisiKimlikNo = (int)Math.Floor(Math.Log10(value)) + 1;
			if (value > 0 && haneSayisiKimlikNo == 9)
			{
				kimlikNo = value;
			}
			else throw new ArgumentOutOfRangeException();
		}
	}
}
Eğer kimlik numara ataması başarılı şekilde yapılmazsa hata fırlatılacak. Bu sayede değişkene kontrollü bir atama sağlanabilir. Bu sayede yazdığımız implement'lere kendi şartlarımızı koyabiliriz, sınırlamalar yapabiliriz.

C# ayrıca property kullanımında kolaylıklar sağlamaktadır. Bir sınıfta alan değişkeni tanımlamanda da sadece property'leri aşağıdaki gibi tanımlayabiliriz:
class Vatandas
{	
	public int KimlikNo
	{
		get; set;
	}
	
	public int dogumYili
	{
		get; set;
	}
}
Bunlar auto-implemented properties olarak bilinmektedir. Sonuç olarak her iki property de okuma ve yazma iznini barındırmaktadır. Yukarı anlattığımız işlevlerde bir farkı yok, sadece tanımlamada daha kısa yoldan bir yöntem sağlamaktadır.
Devamını Oku »

Vim'e Giriş

Vim derslerinin ilk kısmına giriş yapıyoruz. Vim nedir? Vim bir geliştirici editörüdür, kısaca text editör olarak tanımlayabiliriz.

Ancak vim diğer editörlere nazarak direkt olarak kullanıma başlayabileceğimiz bir editör değildir. Bu editörü kullanmayı öğrenmek için istikrarlı bir şekilde öğrenmeye çalışmalıyız.

Vim editörünün iki temel modu bulunmaktadır. Bu modlar, insert ve normal modlardırıdır. insert mode, normal bir şekilde nasıl notepad üzerinde yazı yazıyorsak o işlevselliği sağlamaktadır. normal mode, yazı üzerinden değişiklik yapabilmek için çok daha etkili kullanım yöntemleri sağlayan moddur.

Hangi mode'un aktif olduğunu editördeki alt bardan anlayabiliriz.

Vim Dersleri

Mode değiştirmek için eğer normal mode'a geçilmek istenirse ESC butonuna, insert mode'a geçmek için ise i butonuna tıklanır.

Biz şimdilik i'ye basıp insert mode üzerinden ilerleyelim. insert mode anında editör içinde örnek bir yazı yazalım. Ancak bu yazdığımız yazıda bazı hatalar mevcut. Bu hatalar insert mode aktif iken düzeltebiliriz ancak bunun fare imlecini ya da ok tuşlarını kullanmamız gerekecek. Bunun yerine normal mode'a geçmek ve h,j,k,l tuşları düzeltmeyi deneybiliriz. İlk başta bu durum çok uzun bir yolmuş gibi gelse bile pratiklik kazandıkça ciddi anlamda hız kazandıracaktır ve fareye olan bağımlılığımızı azaltacaktır.

Normal mode'a geçmek için ESC'ye basılır ve imleci h,j,k,l klavye tuşları ile hareket ettirebiliriz.

  • h tuşu, imleci sola hareket ettirir.
  • j tuşu, imleci sağa hareket ettirir.
  • k tuşu, imleci yukarıya hareket ettirir.
  • l tuşu, imleci aşağıya hareket ettirir.

Öğrendiğimiz bu bilgileri kullanarak aşağıdaki yanlış yazılmış metni düzeltelim.

Vim editör kullanımı

Ayrıca w, b, e tuşlarını kullanarak kelimeler arasında hızlıca dolaşabilirsiniz.

  • w tuşu, soldan sağa ve yukarıdan aşağıya olmak üzere kelimelerin baş harfleri üzerine imleç koymamızı sağlar.
  • b tuşu, sağdan sola ve aşağıdan yukarıya olmak üzere kelimelerin baş harfleri üzerine imleç koymamızı sağlar.
  • e tuşu ise soldan sağa ve yukarıdan aşağıya olmak üzere  kelimelerin son harfleri üzerine imleç koymamızı sağlar. Aşağıda olduğu gibi:

Vim klavye tuşları

Bu tuşların önünde katsayı da kullanabiliriz. Örneğin, 10 kelime birden hareket etmek istiyorsak, normal mode'da 10w yazarak 10 kelime birden imleci hareket ettirebiliriz. Farklı olarak, 5b yaparak 5 kelime geriye ya da 7e ile kelimenin son harfine imleç koymak üzere 7 kelime ileri imleci atabiliriz.

10 kere "merhaba" yazdırmak istersek:
  1. normal mode'a geçilir.
  2. 10 yazılır
  3. insert mode'a geçilir.
  4. "merhaba" yazılır
  5. normal mode'a geçilir.
Vim istenilen kadar kelime yazdırma

Şimdilik bu kadar yeterli sanırım, sonraki yazılarda daha fazla özelliğe değineceğiz. Bu aşamada yukarıdaki işlemler ile bol bol egzersiz yapmak Vim üzerinde yetkinliğimizi arttıracaktır.
Devamını Oku »

Python *args ve **kwargs Kullanımı

*args nedir?

*args sınırsız sayıda argüman almamızı sağlar. Fonksiyonun argument bölümünde kullanılır. Ayrıca programın çökmesini engeller. Bazı durumlarda kullanılacak olan argüman sayısı belli olmayabilir. Böyle durumlarda *args kullanmak yararlı olabilir.
def goster(*args):
    for arg in args:
        print(arg)

goster("ahmet", "mehmet", 12)
goster(23, True)
Yukarıda görüldüğü *args kullanımıyla birlikte parametre kısmında istediğimiz sayıda argüman verebiliriz. Şimdi biraz daha detaylandıralım:
liste = ["ahmet", "mehmet", 12]

goster(liste)
Eğer bu şekilde verirsek liste elemanları alt alta sıralanıp gösterilmeyecek. Direkt olarak ['ahmet', 'mehmet', 12] sonucu elde edeceğiz. Çünkü verdiğimiz argüman bir liste olarak görülmüyor. Bu argümanın liste olarak görünmesi için aşağıdaki şekilde bir kullanılmalıdır.
goster(*liste)

**kwargs nedir? 

**kwargs argümanı *args argümanı gibi olmakla birlikte ondan ayrı bir özellik olarak değer atanmış argümanlardır. Kısacası bu argümanlar default olarak tanımlıdır.
def goster_2(**kwargs):
    for e in kwargs.items():
        print(e)

goster_2(pi = 3.14, e = 2.78, g = 10)
Elde ettiğimiz sonuç aşağıdaki gibi olur:
('pi', 3.14)
('e', 2.78)
('g', 10)
Sadece değerleri ekrana yazdırmak istersek e yerine e[1] yazmamız yeterli olacaktır.
Devamını Oku »

Python ile Dosya Oluşturma

Yeni bir proje dosyası oluşturalım. Main.py adında bir dosya oluşturulalım. Python ile dosya oluşturmamız için gerekli fonksiyonu yazalım. Fonksiyon ismini dosyaOlustur olarak belirledik.

Şimdi belli bir aşamada kodlarımızı yazalım. Ayrıca main.py dosyasının main yani ana dosya olduğunu belirtmek için if __name__ == '__main__': koşullu ifadesi yazılmaktadır. Bu sayede dosya çalıştırıldığında direkt olarak bu koşullu ifade altında yer alan fonksiyonlar çalıştırılmış olacaktır.
def dosyaOlustur(ad):
    pass

if __name__ == '__main__':
    dosyaOlustur("deneme")
Dosya işlemleri için os modülünden path sınıfını kullanmamız gerekli:
from os import path
dosyaOlustur fonksiyonunda aşağıdaki geliştirmeler yapılır. Öncelikle parametre olarak dosya adını alıyoruz. Ayrıca bu ad ile oluşturulmuş bir dosya varsa kontrol ediliyor ki bunu path.isFile ile yapıyoruz.
def dosyaOlustur(ad):
    if path.isfile(ad):
        print("Bu ad ile oluşturulmuş dosya zaten mevcut")
    else:
        file = open(ad, "w")
        file.write("merhaba")
        file.close()
        print("dosya olusturuldu")
Program çalıştırıldıktan sonra deneme adında dosya, program dosyamızın bulunduğu dizinde yazılacaktır. Eğer bu ad ile oluşturulmuş bir dosya var ise uyarıda bulunacaktır.
Devamını Oku »

Nasıl Yılan Oyunu Yapılır?

Bu yazı serimizde nasıl yılan oyunu yapılır, onu öğreneceğiz. Yılan oyununu yapmak için belli bir seviye programlama bilgisine ihtiyaç vardır. Kullanılacaklar programlama dili Python ve onun modülü olan oyun geliştirme kütüphanesi Pygame. Pygame hakkında ayrınıtılı bilgiyi web sayfasından edinebilir, ayrıca pygame kullanılarak yapılmış oyun örneklerini inceleyebilirsiniz.

Yılan oyunu yaparken aslında Pygame nasıl kullanılır onu da öğrenmiş olacağız. Bu sebeple yazıları elimden geldiğince ayrıntılı tutmaya çalışıyorum. Ayrıca yazılar belli aralıklarla güncellenebilir ve var olan yazım hataları giderilmeye çalışılacaktır. Yılan oyununu yaparken yazılan kod modüler olmaktan çok ilk başta spagetti bir kod olarak yazılacaktır. Sırasıyla dersler:

Devamını Oku »

Pygame Yılanı Hareket Ettirme

Yılanı hareket ettirmeyi bu yazıda sağlayacağız. İlk olarak Snake sprite sınıfında move adında bir metot oluşturuyoruz. Bu metot event loop içinde kullanılacaktır. Örneğin, oyuncu yukarı tuşuna bastığında move fonksiyonu parametresi y=-1 olmak üzere bir birim yukarı çıkacaktır. Ancak her ne kadar değerler üzerinde değişiklik olsa bile bu durum çizimlere yansımayacaktır çünkü sprite update edilmeden görüntünün değişmesi mümkün değildir. Bu sebeple update adında metot yazılır ve yılan karakterinin ekrandaki konumu görünüm olarak güncellenir:
class Snake(pygame.sprite.Sprite):
    # constructor
    def __init__(self, all_sprites_group, x, y, w, h, color):
        ...
    
    def move(self, x=0, y=0):
        self.x += x
        self.y += y

    def update(self):
        self.rect.x = self.x * 32
        self.rect.y = self.y * 32
Sıra move metotunu oyun döngüsünde yer alan event loop içinde kullanmaya geldi. Oyuncu, yukarı ok tuşuna bastığında y=-1, aşağı ok tuşuna bastığında y=1, sağ ok tuşuna bastığında x=1 ve sol ok tuşuna bastığında x=-1 argümanlarını alacaktır:
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                snake.move(x=-1)
            if event.key == pygame.K_RIGHT:
                snake.move(x=1)
            if event.key == pygame.K_UP:
                snake.move(y=-1)
            if event.key == pygame.K_DOWN:
                snake.move(y=1)
Şimdi oyunu çalıştıralım ve hareket işleminin nasıl gerçekleştiğine bakalım:
Pygame Yılan Oyunu
Görüldüğü gibi yılanı hareket ettirdiğimizde geçtiği her yeri kırmızı yapıyor. Bunun çözümü ise oldukça basit. Her güncelleme esnasında yine aynı şekilde ekranı da siyah renk ile doldurursak çözüm sağlanmış olur:
    # çizim
    display.fill((0,0,0))
    
    for x in range(0, 720, 32):
        ...
    for y in range(0, 480, 32):
        ...

    all_sprites_group.draw(display)
    pygame.display.flip()
Oyunu tekrar çalıştırdığımızda ise aşağıdaki sonucu elde ederiz:
Pygame Yılan Oyunu
Normalde yılan oyununda yılan sürekli hareket eder, oyuncu ise ona sadece yön verir. Ancak şu ana kadar yılanı hareket ettirmek tuşlara tekrar basılı tutmalıyız. Normal sadece bir kere sol ok tuşuna bastığımızda yılan hiç durmadan sol yöne doğru hareket etmeli.

Yön doğrultusunda hareket yapılacağı için dir adında bir özellik tanımlanır Snake sınıfı içinde ve move fonksiyonu aşağıdaki gibi güncellenir, yılan hareket ettikten sonra aktif yönde durmadan hareket etmesi gerektiği için update fonksiyonu da yine aşağıdaki gibi değiştirilir:
class Snake(pygame.sprite.Sprite):
    # constructor
    def __init__(self, all_sprites_group, x, y, w, h, color):
        ...
        self.dir = ""
    
    def move(self, dir):
        self.dir = dir

    def update(self):
        if self.dir == 'left':
            self.rect.x -= 1 * 32
            self.x -= 1 
            self.rect.y = self.y * 32
        if self.dir == 'right':
            self.rect.x += 1 * 32
            self.x += 1 
            self.rect.y = self.y * 32
        if self.dir == 'up':
            self.rect.x = self.x * 32
            self.rect.y -= 1 * 32
            self.y -= 1
        if self.dir == 'down':
            self.rect.x = self.x * 32
            self.rect.y += 1 * 32
            self.y += 1
Nesnenin yönlere göre hareket ettirilmesi için event loop içinde aşağıdaki değişiklikler yapılır:
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                snake.move(dir='left')
            if event.key == pygame.K_RIGHT:
                snake.move(dir='right')
            if event.key == pygame.K_UP:
                snake.move(dir='up')
            if event.key == pygame.K_DOWN:
                snake.move(dir='down')
Oyun çalıştırıldığında ve yılan hareket ettirildiğinde muhtemelen ekranda hiçbir şey görünmeyecektir. Bu durumda yapmamız gereken oldukça basit, kare hızını düşürmek olacaktır. Bunun için tick metotu kullanılacak. İlk olarak clock adında bir zaman nesnesi tanımlanır:
display = pygame.display.set_mode((720, 480))

# **
clock = pygame.time.Clock() 

pygame.display.set_caption('Merhaba Dünya')
Sonrasında oyun döngüsü içinde flip fonksiyonundan sonra tick metotu aşağıdaki gibi kullanılır:
while True:
    for event in pygame.event.get():
        ...
    # güncelle
    ...

    # çizim
    ...
    pygame.display.flip()
    
    clock.tick(5)
clock.tick(5)'in anlamı her bir saniyede sadece 5 frame(kare) gösterileceğidir. Bu kısım oldukça önemli çünkü yılanın hızını yine tick metotuna göre değiştireceğiz.
Devamını Oku »