30 Kasım 2014 Pazar

Engellenmiş Ortamda Yazılım Geliştirmek

Çalışma Ortamı
Savunma sanayindeki bazı yazılım firmaları çalışanlarına doğru dürüst internet erişimi vermezler. Bazı kübiklere internet makineler koyarlar - ki bu makineler genellikle en dandik işe yaramayanlardır. USB'ler etkin değildir, çalışmaz.

Kaynak kodum çalınmasın diye mi ? 
Microsoft kaynak kodunu bir çok kurum ile paylaşıyor. Açık kaynak kodlu bir çok yazılım var. Bu kurumlar kodların çalınmasından korkmuyor mu ?

Çalışanlar internette vakit harcamasın diye mi ? 
Bunu engellemenin çok basit yöntemleri var. Websense gibi bir araç ile bazı siteler engellenir. Hatta şu anda herkes telefon,tablet ile internete bağlanıyor. İnternette vakit harcamak isteyen yine harcar. Bu kişileri engellemenin yolu da yok.

Peki internete erişimi olmayan insanlar nasıl yazılım geliştirecekler ?
Best of the best olduğunu iddia eden bu firmalar yazılım geliştirme konusunda bu kadar engel koyduktan sonra ne elde edeceklerini sanıyorlar ?

29 Kasım 2014 Cumartesi

CMMI - Süreç Varlıkları

Süreç Varlıkları (Organizational Process Assets) bir çok firmanın CMMI yapısına geçince hayata geçirdikleri bir portal.

Genellikle 4 kademeden oluşuyor.

Policies -> Processes/Practices -> Work Instructions/Procedures -> Enablers/Templates

Policies
Identify the organization's expectations for establishing and maintaining the process

Processes/Practices
Often high level process descriptions whereas Work Instructions/Procedures provide more detailed steps related to the process

Enablers/Templates
Can be any kind  of process aid that helps carry out the process and can include tool guides, or templates to help build related documentation

Süreç varlıkları da "review", "approval", "release" aşamalarından geçerler.

Yazılım Arayüzü

Giriş
Yazılım arayüzleri için hazırlanan belgelere bir çok farklı isim verilebiliyor. Software Interface Control Document (ICD), Interface Design Document (IDD) gibi isimler farklı yerlerde karşımıza çıkabilir. Hepsi üç aşağı beş yukarı aynı şeyi yani formatlı mesajları kast eder. Ben bu yazıda "ICD" kelimesini kullandım.

Interface Control Document Nedir?
Interface Control Document (ICD) genellikle elektriksel arayüzler için kullanılır.Yazılım arayüzleri için hazırlanan belgelere de Software ICD deniliyor.

IDD Nedir?
Interface Design Document yazılım arayüzünü belirtir.

Data Transfer Object Nedir?
Ben ICD ile Data Transfer Object (DTO) kavramını birbirine çok yakın buluyorum. DTO klasik kullanımında yazılım servisleri veya katmanları arası veri aktarımı için tanımlanır. ICD ise farklı sistemler arası veri aktarımı için kullanılır. DTO'nun Serialize(), Deserialize() metodları olması gerekmez.

Bitwise ICD
Bir çok iletişim yolu düşük bant genişliğine sahip olduğu için formatlı mesajları sıkıştırmak gerekir. Bu yüzden mesaj alanları bit bit tanımlanırlar. Bitleri engineering formata çevirmek için iki yöntem var.

Low Level ve High Level ICD tanımlamak
Bu yöntemde Low Level ICD bit seviyesinde mesajları okuma yazma işleminden sorumludur.
High Level ICD ise Low Level ICD mesajlarını resolution ve offset değerleri ile çarpıp bölerek engineering formata çevirir.  Ben bu yöntemi daha doğru buluyorum.

Not : Resolution (bazı projerlerde scale de deniyor ki bence scale başka bir şeyi ifade eder) bir bit ile temsil edilebilen en küçük değer anlamına gelir.

Low level  ve High Level'ı birleştiren tek bir ICD tanımlamak
Bu yöntemde her bir mesaj alanı bir struct veya class olarak tanımlanır. Bu sınıfların scale ve offset alanları vardır. Sınıfa değer atanınca scale ve offset değerleri ile çarpıp bölerek engineering formata çevirir. Örnek bir sınıf aşağıda.

class MyInt32 {
 public :
   int32_t m_Value;
   double m_Scale;
   double m_Offset;

  void operator= (int value){
    m_Value = (value * m_Scale) + m_Offset;
  }
}

Bytewise ICD
Bantgenişliği düşük olmayan iletişim yollarında bytewise ICD tanımlanır. Bu ICD mesajlarında int, double gibi büyük tipler kullanılabilir.

ICD ve Protokol
Bir çok iletişim protokolü gerçek verinin yanında ek şeyler de gönderir. Örneğin gerçek veri zarflanabilir, daha küçük parçalara ayrılabilir vs. ICD mesajlarını iletişim protokolüne çevirmek için protokolü gerçekleştiren sınıflar yazmak gerekebilir.

Header Örneği
Message ID : Hangi mesaj olduğunu anlamak için kullanılır. Aşağıda bu alanı kullanan basit bir örnek var.
protected void decode(UnparsedPacket msg, List<Object> out) throws Exception {
        switch(msg.id){
            case FooPacket.ID:
                FooPacket fooPacket = new FooPacket(msg.frame);
                out.add(fooPacket);
                break;
            case BarPacket.ID:
                BarPacket barPacket = new BarPacket(msg.frame);
                out.add(barPacket);
                break;
        }
 }

Message Size : Mesajın byte cinsinden toplam büyüklüğü. Eğer UDP gibi parçalanmaya izin vermeyen bir transport kullanılıyorsa bu alana gerek olmayabilir. TCP gibi transportlarda bu alan ileride ICD'nin değişebileceği de düşünülerek konulursa faydalı olur.

ICD Mesaj Sınıfları
Genellikle sadece Serialize (Stream s), Deserialize (Stream s), ToString() gibi metodlara sahip olan sınıflardır.  Kullanılan programlama diline göre stream sınıf hiyerarşisini de kodlamak gerekebilir.

BitStream, LittleEndianStream, BigEndianStream gibi streamleri bazı programlama dillerinde mevcut olmayabiliyor. Bu durumda hiyerarşiyi kendimiz kurmak zorunda kalırız.

Ayrıca ICD mesajlarını, abstract bir sınıf veya arayüzden türetmek te programlamayı kolaylaştırır.

Serialize Metodu
C++ için yazıyorsak
void MyMessage::Serialize (stream& s);
şeklinde yazılabilir.


ToString metodu
C++ için yazıyorsak
void MyMessage::ToString (stringstream& s);
şeklinde yazılabilir.

ICD ve Range Check
Eğer mesajların hatalı gelebileceği düşünülüyorsa, ICD mesajlarına hatalı durumları yakalayan range check kodları eklenir

ICD ve Logical Check
Bu tür mantıksal kontrolleri ICD mesajlarına eklemek kolay olmayabilir. Gerekirse ICD mesajlarını işleyen katmana dahil edilmelidir.

ICD ve Request Response
Bazı ICD'lerde gönderilen isteğe karşılık Response gönderilir. Bu tür belgelerde hangi isteğe hangi cevap gönderildiğini gösteren bir akış diagramı (sequence diagram) faydalı olur.

İstek ve cevabı eşleştirmek için istek içine sırayla artan bir RequestID yazılır. Gönderilen cevap içine de aynı RequestID yazılarak istek ve cevap eşleştirilir.

ICD ve Surrogate Key
Bazı ICD'ler nesneler üzerinde CRUD işlemi için kullanılır. Eğe karşı sistem, benim yazılımımda CRUD işlemi yapıyorsa, her nesneye bir SurrogateKey verilmesi iyi olur. Benim sistemim ile karşı sistemin yarattığı nesneleri birbirlerinden ayırmak için Surrogate Key iki kısma bölünebilir. Öreğin 0- 100 arası değerler benim, 100-200 arası değerler karşı sistemin olabilir.


ICD ve Acknowledgement
Bazı ICD'lerde gönderilen komuta karşılık Acknowledgement gönderilmesi istenir. ACK mesajında mesajın alındığı belirtilir. Bazen de Response gönderilmeyen durumlarda mesajın işlenip işlenemediği belirtilir.

Internal Mesaj Yapısına Çevirmek
Formatlı ICD mesajı okunduktan sonra yazılımda bir şekilde saklanması gerekir.

Clone Yöntemi
Kullanılabilecek en kolay yöntem ICD mesajını ve Internal mesajı ortak bir sınıftan türetmek olabilir.

     ---->BaseClass<----
     |                                 |
            ICDClass                     InternalClass
Bu yöntemde ICDClass kendisi kullanmasa bile InternalClass'ın ihtiyaç duyduğu alanları da görür ve bilir.

Field Copy Yöntemi
Biraz daha zor bir yöntem ise ICD mesajlarını dizi şeklinde çekirdeğe iletmek. Bu yöntemde çekirdek ICD mesajlarını kendi içindeki yapılara yapıştırır.

ICD Arayüz Bileşeni --- ICD mesaj Dizisi ----> Çekirdek

Bu yöntem ise çekirdek kodunda Clone() yerine teker teker nesnenin alanlarının kopyalaması yapıldığı için hata yapmaya müsaittir.

ICD Arayüzü İçin Yazılım Bileşeni

Yazılımın çekirdeği ile arayüz arasına ICD Arayüzü Yazılım Bileşeni yerleştirmek iyi bir fikir. Böylece çekirdek işlev ICD değişikliklerinden mümkün olduğunca yalıtılmış olur.

SIU 
Sub-System Interface Unit : Genellikle sadece mesaj dönüşümü yapan, akıllı olmayan yazılımlardır

SAU
Sub-System Adaptation Unit : SIU'dan akıllı olan yazılımlardır. Mesajları gerekirse parçalar veya birleştirebilirler.


ICD Mesaj Dizisinin Kısmi Gelmesi
Özellikle bant genişliğinin düşük olduğu sistemlerde ICD mesaj dizisi örneğin 5 parçadan oluşsa bile tasarruf için sadece güncellenmek istenen parçanın gönderilmesi söz konusu olabilir. Bu durumda ICD arayüz sisteminin önceden gelmiş olan bilgiyi kaybetmemek için ICDClass nesnesini doldurmaya başlamadan önce mevcut son halini okuması ve yeni gelen mesaj ile doldurulmuş nesneyi güncellemesi gerekebilir.

ICD Mesajlarının Gönderilmesi
Havadan yapılan iletişim sistemlerinde genellikle aynı paket bir kaç defa tekrarlanır. Farklı zamanlarda yapılan bu gönderimin amacı herkesin mesajı alabilmesini sağlamaktır. ICD arayüz yazılımı bir aktarım kuyruğu kullanarak mesajların gönderilmesi zamanını ve kalan sayacı tutabilir. Adil kullanım kotası koyarak gönderenleri yavaşlatabilir. Daha fazla para ödeyene öncelik tanıyabilir vs.

Bridge Yazılımlar
Bazı yazılımlar sadece iki ICD arasında dönüşüm yapmak için vardır. Bu tür yazılımlara bridge (köprü) denir. Statefull ve stateless olabilirler.

Statefull Sistem
Statefull sistemler genellikle belleklerinde tuttukları bilgiyi süzerek daha küçük listeler halinde karşı sisteme gönderirler. Liste gönderimi periyodik veya sorguya dayalı olabilir.

Stateless Sistem
Stateless sistemler belleklerinde bilgi tutmazlar. Gelen mesajı dönüştürerek bir kuyruğa atarlar. Kuyruğu okuyan bir başka thread ise diğer sisteme gönderir.


ICD Toplantıları
Toplantı öncesinde konuşulacak konular ve çözüm önerileri hazırlanırsa süreç hızlanır. Bir çok toplantı gündem ve çözüm önerisi hazırlanmadığı için faydasız hale geliyor.

Toplantılarda Toplantı Katılım Formu ve Toplantı tutanağı doldurulur.

26 Kasım 2014 Çarşamba

Gof - Singleton Örüntüsü

Not1 : GoF Tasarım Örüntüleri yazısına bakabilirsiniz.
Not 2: Singleton aynı zamanda Multiton örüntüsü ile kardeştir.

Gang of Four
Tasarım örüntülerinin amaçlarından bir tanesi low coupling, high cohesion'a sahip kodlama yapmak.

High Coupling (Çok Fazla Bağımlılık) Örneği
Örnekte bir sınıf değişince bir başka sınıfın da etkilenmesi gösteriliyor. Bu durum high coupling için tipik bir sonuç.

Low Coupling (Düşük Bağımlılık) Neden Lazım ?
Yazılım zaman içinde değişir. Değiştikçe de birbirlerine bağımlı olan nesneler, katmanlar da değişirler. Her değişikliğin maliyetini azaltmak için bağımlılıkların gevşek olması gerekir. Bu yüzden low coupling'in ilk ve en önemli prensibi arayüzler tanımlayarak bu arayüzleri gerçekleştiren metodlar da değişiklik yapmaktır. Bir diğer yöntem ise Encapsulation kullanmaktır. Encapsulation ile diğer sınıfın içini bilmeden örneğin process() isimli bir metodunu çağırarak çalışırız.

Singleton
Singleton şu özellikleri taşır
  • Accessible via a global, static instance field
  • Created either on program initialization or upon first access
  • No public constructor (cannot instantiate directly)
  • Never explicitly freed (implicitly freed on program termination)
Şu dezavantajlarla gelir
  • Inability to use abstract or interface classes (Eğer doğru kullanılırsa bu madde ortadan kalkabilir)
  • Inability to subclass
  • High coupling across the application (difficult to modify)
  • Difficult to test (can't fake/mock in unit tests)
  • Difficult to parallelize in the case of mutable state (requires extensive locking)

Kullanım Yerleri
Lookup işleri için kullanılabilir.

Singleton ve Arayüz
Örnekte singleton ve arayüzün nasıl kullanılacağı gösteriliyor.
class ServerFactory
{
    public:
        // By default return a RealServer
        ServerInterface& getServer();

        // Set a non default server:
        void setServer(ServerInterface& server);
};

class ServerInterface { /* define Interface */ };

class RealServer: public ServerInterface {}; // This is a singleton (potentially)

class TestServer: public ServerInterface {}; // This need not be.
Bir başka örnekte Singleton preprocessor kullanılarak FileSystem arayüzünün farklı gerçekleştirimlerini dönüyor.

FileSystem& FileSystem::instance()
{
  #if PLATFORM == PLAYSTATION3
    static FileSystem *instance = new PS3FileSystem();
  #elif PLATFORM == WII
    static FileSystem *instance = new WiiFileSystem();
  #endif

  return *instance;
}

Singleton Kullanmamak İçin
Şu yöntemler kullanılabilir.

  • Pass it around
  • Create a context object
  • Put it in base class
  • Dependency Injection veya Service Locator
Context Nesnesi Çözümü
class World
{
public:
  static World& instance() { return instance_; }

  // Functions to set log_, et. al. ...

  Log&         getLog()         { return *log_; }
  FileSystem&  getFileSystem()  { return *fileSystem_; }
  AudioPlayer& getAudioPlayer() { return *audioPlayer_; }

private:
  static World instance_;

  Log         *log_;
  FileSystem  *fileSystem_;
  AudioPlayer *audioPlayer_;
};
Daha sonra context'e şöyle erişiliyor
World::instance().getAudioPlayer().play(VERY_LOUD_BANG);


Base Class Çözümü
Örnek:
class GameObject
{
protected:
  Log& getLog() { return log_; }

private:
  static Log& log_;
};

class Enemy : public GameObject
{
  void doSomething()
  {
    getLog().write("I can log!");
  }
};

C++
Kural 1
Default constructor her zaman private olmalıdır.

Kural 2
"copy constructor" ve "assignment operator" metodlarını private yapmak gerekir. C++11 ile copy constructor'ı silmek için şöyle yapılır.
Singleton(const Singleton&) = delete;
Bunu yapmazsak bizim singleton olduğunu düşündüğümüz bir nesne kopyalanabilir.
Singleton * s = Singleton::getInstance();

Singleton copy = *s;   // <-- invokes copy constructor
veya
Singleton s = Singleton::getInstance ( );
veya
Singleton * s1 = Singleton::getInstance();
Singleton * s2 = Singleton::getInstance();

*s1 = *s2;    // <-- invokes assignment operator
Kural 3
Singleton pointer veya referans olarak döndürülebilir. Ben referans olanını seviyorum.

Yöntem - 1 : Static Sınıf Değişkeni Olarak - Lazy
Bu yöntem klasik olanı. Lazy kullanımda singleton'a ilk erişen kişi nesneyi ilklendirir. Multi-thread uygulamalarda sorun çıkarır.

class Singleton
{
public:
  static Singleton& instance()
  {
    // Lazy initialize.
    if (instance_ == NULL) instance_ = new Singleton();
    return *instance_;
  }

private:
  Singleton() {}

  static Singleton* instance_;
};

Yöntem - 2 :Local Static Değişkeni Olarak
Bu örnekte, singleton nesnesi statik olarak instance() metodu içinde tanımlanıyor. Local static değişkenler multi-threaded bile olsa bir kere yaratıldığı için bu yöntem thread-safe.
class Singleton
{
private:
   Singleton() = default;
   Singleton(const Singleton&) = delete;
public:
   static Singleton& instance() { static Singleton z; return z; }
};
Bir başka örnekte nesne heap'te yaratılyor.
class Singleton
{
public:
  static Singleton& instance()
  {
    static Singleton *instance = new Singleton();
    return *instance;
  }

private:
  Singleton() {} 
};

Yöntem - 3 :Tüm Alanları Static Olarak
Örnek ver

Java
Java Singleton Örnekleri yazısına taşıdım.

C#
Örnek'te bir ata sınıftan kalıtma gösterilmiş:
Ata sınıf:
public abstract class Singleton<ClassType> where ClassType : new()
{
  static Singleton()
  {
  }

  private static readonly ClassType instance = new ClassType();

  public static ClassType Instance
  {
    get
    {
      return instance;
    }
  }
}
Kalıtan sınıf:
class Example : Singleton<Example>
{
  public int ExampleProperty { get; set; }
}
Kullanım:
public void LameExampleMethod()
{
  Example.Instance.ExampleProperty++;
}




Multiton

Giriş
Multiton, Singleton örüntüsünün kardeşi kabul edilebilir. Genellikle bir HashTable içeren sınıf ile gerçekleştirilir. Örnek:
Class Multiton
{
 Key key;

 private static Map<Key,C> cs = new HashMap<Key,C>();

 private C(Key key)
 {
  // this takes a long time
 }

 synchronized static Multiton get(Key key)
 {
  Multition c = cs.get(key);
  if(c==null)
  {
   c = new Multiton(key);
   cs.put(key,c);
  }
  return c;
 }

}





25 Kasım 2014 Salı

Equals İşlemleri

Not : Bu yazıyla ilgili olarak basit hash fonksiyonlarını açıklayan Kripto başlıklı yazıya göz atabilirsiniz.

Giriş
Java ve C# dillerinde Equals() ve HashCode() metodları, özellikle hash tabanlı veri yapılarında kullanılıyorlar. Dolayısıyla yazdığımız sınıflarda bazen Equals ve HashCode metodlarını override etmek gerekir.

HashCode 32 bittir
Java'daki HashCode() ve C#'taki GetHashCode() 32 bitlik bir int döndürürler. Dolayısıyla long gibi 64 bit olan tiplerde hash çakışması kaçınılmazdır. Buna Pigeonhole principle denir.

Tek Bir Alana Göre HashCode Kullanmak
Eğer sınıfın tek bir alanına göre hash almak istersek yapmamız gereken işlem çok basit
@Override
public int hashCode() 
{
    return someFieldValue.hashCode();
}

Bazı Sınıfların Equals Metodu Vardır
Array sınıfı
Arrays.equals(arr1,arr2)

Hash ve Sıralama Farklı Şeylerdir
Hash tabanlı veri yapılarında C# dilindeki IComparable veya Java'daki karşılık gelen arayüzü kullanmak işe yaramaz, çünkü bu arayüz sıralama yapmak için işe yarar.

Her iki yöntem farklı amaçlar için kullanılsa da  Equals ve IComparable arayüzlerinin ortak noktası mevcut. Bu da iki nesnenin birbirlerine eşit olup olmadığının belirlenmesi.

İşte bu noktada bazı sınıflarda equals() ve compareTo() metodları tutarsız sonuçlar dönebiliyor. Örneğin equals() metodu iki sınıfı farklı olarak görürken, compareTo metodu eşitmiş gibi sonuç dönebiliyor.
Aşağıda bu durumu gösteren bir örnek var.

BigDecimal
equals() metodu - kullanmamak daha iyi
BigDecimal sınıfının boolean equals(Object x) metodunu kullanırken dikkatli olmak lazım çünkü scale değerleri farklı olan iki BigDecimal aslında matematiksel olarak aynı değere sahip olsalar bile farklı gibi değerlediriliyorlar.

Yine buradan aldığım örnekte testlerin istenilen sonucu vermediğini görmek mümkün. Çünkü BigDecimal sınıfının equals() metodu sayının nasıl temsil edildiğini dikkate alıyor.


compareTo - kullanmak daha iyi
İki BigDecimal sınıfı karşılaştırmak için int compareTo(BigDecimal val) metodunu kullanmak lazım.
Ancak org.apache.commons.lang.builder.EqualsBuilder sınıfı int compareTo(BigDecimal val) metodunu kullanmıyor. Dolayısıyla LANG-476'de gösterildiği gibi bazı durumlarda yanlış sonuç dönebiliyor.

Float veya Double
== metodu - sayıları sıralarken kullanmamak daha iyi
== metodu total ordering yöntemini esas almıyor. Total ordering yönteminde bir sayı dizisini sıralarken -0.0 < +0.0 ve NaN == NaN şeklinde kabul edilir. Matematiksel olarak -0.0 her zaman +0.0'a eşit olmasına rağmen ve NaN hiçbir şekilde bir başka NaN ile eşit olamazken, küçükten büyüğe doğru sıralamada eksi sayının artı sayıdan daha önce gelmesi ve NaN'nin bir başka NaN ile eşit kabul edilmesi istenir. İşte bu yüzden sayıları sıralarken == operatörü yerine compare() metodunu kullanmak lazım.
Float.NaN == Float.NaN // false
-0.0d == 0.0d // true

Not : IEEE 754 standardında == karşılaştırmasının herhangi bir yanı NaN ise sonuç her zaman false döner.

If either operand is NaN, then the result of == is false but the result of != is true.
Ancak compareTo aşağıdaki gibi çalışır. Eğer iki değer birbirlerinden küçük veya büyük değilse, -0.0, +0.0, veya NaN ise bit gösterimleri karşılaştırılır.



Apache Commons
EqualsBuilder ve HashCodeBuilder
Burada Apache Commons, Eclipse tarafından üretilen kod ve Guava'yı karşılaştıran örnekler var.
EqualsBuilder ve HashCodeBuilder aşağıdaki gibi fluent interface şeklinde kullanılıyorlar.

EqualsBuilder().append(...).append(...).isEquals()
HashCodeBuilder().append(...)..append(...).toHashCode() ;
şeklinde kullanılıyor.

Guava
Objects.equal ve Objects.hashCode metodları kullanılıyor. Örnek:

Guava ile gelen HashCode sınıfı içinde bir byte array tutuyor.

C#
C# Equals() ve HashCode() metodları Java ile aynı. Burada bir  örnek var.