Showing posts with label Domain Driven Design. Show all posts
Showing posts with label Domain Driven Design. Show all posts

Monday, November 01, 2010

Kenapa perlu elakkan Anemic Domain Model

Salam

Aku sebelum ini percaya Anemic Domain Model tidak bagus jika ada dalam sesuatu domain model design/code dan aku masih lagi percaya cuma kini terdapat sedikit perbezaan dengan apa yang aku buat dalam sotware project terbaru. Ianya berkisar kepada "What System DOES" dan "What system IS". So anemic domain model nie hampir definasi apa yang dikenali "What system IS". Daripada Martin Fowler, symptom Anemic Domain Model ialah

"The basic symptom of an Anemic Domain Model is that at first blush it looks like the real thing. There are objects, many named after the nouns in the domain space, and these objects are connected with the rich relationships and structure that true domain models have. The catch comes when you look at the behavior, and you realize that there is hardly any behavior on these objects, making them little more than bags of getters and setters. Indeed often these models come with design rules that say that you are not to put any domain logic in the the domain objects. Instead there are a set of service objects which capture all the domain logic. These services live on top of the domain model and use the domain model for data".

Aku semakin slow dalam coding dan semakin slow juga nak faham code, so kalau code yang terlalu banyak tempat business algorithm dimana aku kena refer pada object A dan kemudian pergi ke object B, menjadikan aku kurang efficient so tak 1Malaysia lah cam nie. 1Malaysia pencapaian diutama so begitu jugalah halnya dalam code, code yang senang dibaca dan efficient sangat2 diperlukan, tapi ini semua abstract. Mungkin senang bagi developer Najib (bukan nama sebenar) tidak mudah untuk developer bernama Anwar (pun bukan nama sebenar). Cuma kita boleh ambil tahap pertengahan dimana indicator yang dirasakan setiap developer tu boleh memahami at least 60%-70% code yang awal apabila diberi code untuk dibaca.

So aku sudah pun bermula dengan pecahkan object2 aku kepada 2 bahagian. Basic object ialah ada attribute dan ada behaviour. So sekarang object2 aku buat dah seakan kembali menjadi anemic domain model percayalah. Cuma perbezaan dengan symptom anemic domain model sebelum ini ialah object attribute dan behavior tidak akan bersatu dan sebaliknya object lain dikenali sebagai "services" yang akan memainkan peranan menGALAS tanggungjawab untuk melakukan perbuatan baik dan buruk (method/behaviour object ada buruk dan baik gak). So yang macam nie memang aku bangkang. Aku tak boleh terima sesorang yang ada maklumat tetapi yang akan buat kerja orang lain berdasarkan maklumat tersebut. Jadi apa yang aku perlukan ialah di masa design code aku dipecahkan tetapi pada masa runtime atau pada masa diperlukan aku boleh dapat behavior2 tersebut. Itulah bezanya "runtime".

So aku boleh reuse behavior tu kepada mana-mana object yang perlu. Ambil contoh mudah

Manusia (Person) ada Nama Rasmi dan Nama panggilan, so aku ada satu satu behaviour yang cantumkan nama rasmi dan nama panggilan untuk return string. Jadi behaviour tu aku boleh pakai re-use kembali pada mana-mana object yang mempunyai structure contract yang sama. Orang yang biasa dgn OOP maybe dah terbayang untuk membuat satu interface dan ada class yang implement tapi bagi aku yang macam nie susah. Aku inginkan cara yang lebih mudah dan fluent.


class Orang
{
string Nama;
string Panggilan;
}

class Kereta
{
string Name
string Code
string Panggilan;
}

Maybe ada suggestion untuk buat interface dan setiap object tu implement interface, tapi bagi aku cara nie panjang macam code kat bawah ni.

interface Cantum
{
string CantumNamaPanggilan(string name,string panggilan);
}

class Orang :Cantum
{
string CantumNamaPanggilan(string name,string panggilan)
{
///
}
}

class Kereta : Cantum
{
string CantumNamaPanggilan(string name,string panggilan)
{
///
}
}

Dan mungkin ada yang suruh letak implementation dalam abstract class, cuma bagi aku limitation class hanya boleh extend pada satu abstract class, kalau ada bnyk behavior takan nak letak semua dalam abstract class tu. Ada cara lain tak yang aku tak nampak sebelum aku bagi cara yang aku cuba nak buat (belum diuji tahan peluru dan api :)?

Friday, April 03, 2009

Single Responsibility Principle

Aku terbaca satu artikel Would Your Objects Praise You?
cuma aku kurang setuju dengan apa yang mamat nie cakap. Ada benarnya tapi tak semuanya betul konsep tu. Apa yang cuba disampaikan ialah konsep Single Responsibility Principal.

The single responsibility principle states that every object should have a single responsibility, and that all its services should be narrowly aligned with that responsibility. [Wikipedia].

Ok, cara dan formula yang di gunakan cukup menarik dan bagus dan aku pun rasa sesuatu yang reasonable unutk digunakan apabila buat domain model anlysis. Formula yang cuba diketengahkan ialah

Can a [type] [action in the infinitive] itself?

So dalam artikel tersebut , mamat nie ambil contoh sebuah kereta


Jadi berdasarkan method yang ada pada kereta tersebut kalau dilihat memang menyalahi SRP. Sebab class Car coupling dengan telalu banyak kerja yang perlu dilakukan. Cuba fikirkan sejenak apa tugas sebuah kereta. Jawapan dia abstract dan berlainan bagi setiap orang, sebab itu SRP nie kalau mengikut pencetus principle yang dekenali sebagai Pakcik Bob pattern yang simple tapi susah untuk dapat yang betul betul ngam.

"The SRP is one of the simplest of the principle, and one of the hardest to get right. Conjoining responsibilities is something that we do naturally. Finding and separating those responsibilities from one another is much of what software design is really about".

Berbalik semula kepada persoalan kereta tadi. Mamat Brian nie cadangkan untuk dapatkan cara yang betul penggunaan SRP ialah dengan melakukan pertanyaan seperti berikut:

  • Can a car change gears by itself?
  • Can a car change a radio station by itself?
  • Can a car drive itself?
  • Can a car idle by itself?
  • Can a car park itself?
  • Can a car start itself?
Dan ini jawapan bagi soalan-soalan tersebut

Unless you’re the lucky owner of the Knight Rider, you probably answered ‘NO’ to a few of these questions. For every question or observation you have answered ‘NO’, you should more than likely refactor the class and move some of its responsibilities elsewhere. But where exactly can you move these responsibilities? Well, before we dive to some of these answers, let’s see if we can directly some of the original questions pertaining to our Car class:
  • Can a car change gears by itself? ANSWER: Sure, if it has an automatic transmission. Otherwise, only the driver can shift gears.
  • Can a car change a radio station by itself? ANSWER: Nope, only the driver (or the passenger) can change the radio station.
  • Can a car drive itself? ANSWER: Not unless it’s KITT! Only a driver can drive a car.
  • Can a car idle by itself? ANSWER: Sure it can.
  • Can a car park itself? ANSWER: Nope! Only a driver can know how to park a car.
  • Can a car start itself? ANSWER: Uh, no. Once again, only the driver can start the car.
Nie pula jawapan aku. Ya memang betul kereta tak boleh change gear sendiri tapi kereta simpan maklumat tentang gear, jadi jika kereta tak boleh nak buat tugas change gear tapi kereta ada maklumat tentang gear jadi nak buat macam mana nie?.. Kalau tanya BIJAN dia jawab kita perlukan kereta yang ada ciri GLOKAL .. hahahah (iklan sebentar). So mamat Brian nie kata keluarkan tugas tersebut kepada seorang Driver (role). Aku tak setuju sangat. Nie contoh yang dia beri dan apa yang diberi sebenarnya valid dan boleh digunakan cuma jika diteliti dengan lebih detail pasti jawapan lain sedikit.


Disini kena faham konsep message to object. Persoalan Driver perlu ada atau tidak masih lagi abstract kepada Domain Expert dan juga untuk apa application ini dihasilkan. Kalau application nie dihasilkan untuk stimulate Video Game dimana dari screen hanya nampak kereta yang boleh dipandu maka class Driver tidak diperlukan sebaliknya class Driver itu digantikan dengan Application Service - CarService.

Ini pula pada pendapat aku, yang dikategorikan sebagai programmer kampung. Untuk mengikut konsep SRP kita perlu pecahkan tugas-tugas tersebut kepada yang berhak, jangan tamak nak ambil tugas orang lain, nasib baik BIJAN tak tamak dia ambik sikit je. Dari class Car kita akan pecahkan kepada class Gear, class Radio, class Engine.


//Car.cs

public class Car

{

public Gear Gear { set; get; }

public Engine Engine { set; get; }

public Radio Radio { set; get; }

public void Drive()

{

}

}


//Engine.cs

public class Engine

{

public void Start()

{

}

}

//Gear.cs

public class Gear

{

public void ChangeGear()

{

}

}

//Radio.cs

public class Radio

{

public void ChangeRadioStation()

{

}

}


//CarService.cs


public class CarService
{
public Car Car { set; get; }

public void ChangeGear()
{
Car.Gear.ChangeGear();
}

public void ChangeRadioStation()
{
Car.Radio.ChangeRadioStation();
}

public void StartEngine()
{
Car.Engine.Start();
}

public void Drive()
{
Car.Drive();
}
}