kaya gibi sağlam yazılım projelerine İmza atmanın 5 prensibi
TRANSCRIPT
Kaya Gibi Sağlam Yazılım Projelerineİmza Atmanın5 Prensibi
İbrahim GündüzTemmuz 2015 @ PHPKonf
İbrahim GündüzYazılım Geliştirici
http://tr.linkedin.com/in/ibrahimgunduz
https://github.com/ibrahimgunduz34
https://twitter.com/ibrahimgunduz34
http://www.ibrahimgunduz.net/
"... the design of a software project is documented primarily by its source code."
Robert C. Martin
“Biz döküman yazmıyoruz, iş yapıyoruz”
KÖTÜ TASARIM ÇÜRÜR!!!
ÇÜRÜYEN TASARIM KOKAR!!!
Esnemezlik(Rigidity)
Esnemezlik (Rigidity)
● Kaynak kodunda değişikliğe karşı artan zorlaşma eğilimi
● Tek bir değişikliğin bile başka pek çok modülde değişikliğe neden olması
● Geliştirme süresinin gitgide artması
Kırılganlık(Fragility)
Kırılganlık (Fragility)
● En küçük değişiklikle bile uygulamada pek çok noktada kırılabilme eğiliminin artması
● Yapılan değişiklikle doğrudan ilgisi olmayan farklı noktada meydana gelen kırılmalar
● Yapılan her hata giderme işlemi ile birlikte olası beklenmedik hataların oluşması ihtimalinin artması
Taşınamamazlık(Immobility)
Taşınamamazlık (Immobility)
● Modüller arası yüksek bağımlılık
● Taşınamayan, mevcut veya başka bir proje tarafından kullanılamayan kod blokları
● Gereksiz kod tekrarları
Akışkanlık Direnci(Viscosity)
Akışkanlık Direnci (Viscosity)
● Tasarımı koruma yoluna gitmek, gelişi güzel iş yapmaktan daha zor hale geldiğinde akışkanlık direnci yüksektir.
● Geliştirme ortamının yavaş yada elverişsiz olması geliştiricilerin gelişi güzel iş yapma eğilimini arttırır.
Gereksiz Tekrar(Needless Repetition)
Gereksiz Tekrar (Needles Repetition)
● Tasarımın, tek soyutlamanın içinde tekrarlanan yapılar içermesi
● Geliştiricinin kopyala/yapıştır kavramını su istimal etmesi
● Tekrarlanan kodla anlaşılmaz ve bakımı zor hale gelen sistem
Gereksiz Karmaşa(Needless Complexity)
Gereksiz Karmaşa (Needles Complexity)
● Proje, anlaşılması güç ve hiçbir zaman kullanılmayan yapılarla doludur.
● Kullanışsız kod blokları karmaşa hissi uyandırır.
“Any fool can write code that a computer can understand. Good programmers can write code that humans can understand.”
Martin Fowler
S.O.L.I.D. Prensipleri
SOLID PrensipleriNedir ?Robert Martin sunumu ile ortaya çıkan bağımlılık yönetimi biçiminin baş harfleridir.
Ne Sağlar ?● Gevşek bağlara sahip● Yeniden Kullanılabilir ● Kolaylıkla test edilebilir● Gerektiğinde rahatlıkla
bakım yapılabilir● Yüksek uyumluğa sahip
“S”Single ResponsibilityTekil Sorumluluk
Single Responsbility
Her sınıfın ve metodun tek bir sorumluluğu olmalı.
class UserManager
{
public function register($email, $fullname, $password)
{
//validasyon
if( !$email || !$this->isEmail($email)) {,
throw new ValidationError('Email must be valid email address.');
}
if(!$fullname || len($fullname) < 20 || len(split(' ', $email)) < 2) {
throw new ValidationError('Fullname must be valid name.');
}
if(len($password) < 6 || len($password) > 30) {
throw new ValidationError('Password length must be greater than six character and less than thirty character.');
}
//veritabaninda kullanici kaydi olusturuluyor
try {
$user = new User();
$user->setName($fullname);
$user->setEmail($email);
$user->generatePassword($password);
$user->persist();
$user->flush();
$mailer = new Mailer();
$mailer->send($user->getEmail(), 'Registration is completed successfuly.', 'bla..bla...'
);
} catch(DatabaseError $error) {
Logger::exception($error);
throw new SystemError('User registration is failed.');
}
}
}
class UserManager
{
private function createUser($email, $fullname, password)
{
$user = new User();
$user->setName($fullname);
$user->setEmail($email);
$user->generatePassword($password);
$user->persist();
$user->flush();
return $user;
}
public function register($email, $fullname, $password)
{
//validasyon
$validator = new UserRegistrationValidator($email, $fullname, $password);
$validator->validate();
//veritabaninda kullanici kaydi olusturuluyor
try {
$user = $this->createUser($email, $fullname, $password);
$eventDispatcher->dispatch('user.registred', new UserRegisterEvent($user));
return true;
} catch(DatabaseError $exc) {
Logger::exception($exc);
throw new SystemError('User registration is failed.');
}
}
}
“O”Open-Closed
Açık / Kapalı
Open - Closed
Kaynak kodu genişlemeye açık, değişime kapalı olmalıdır.
class SaleRules
{
public function calculateDiscount($customerGroup, $totalAmount)
{
if($customerGroup == CustomerGroup::STANDARD) {
$discount = $totalAmount * 0.95 + 3 / 2
} elseif ($customerGroup == CustomerGroup::SILVER) {
$discount = ...
} elseif($customerGroup == CustomerGroup::PLATIN) {
$discount = ...
} elseif($customerGroup == CustomerGroup::GOLD) {
$discount = ...
}
return $discount
}
}
interface CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount);
}
class StandardGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SilverGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SaleRules
{
public function calculateDiscount($rule, $totalAmount)
{
return $rule->calculateDiscount($totalAmount);
}
}
“L”Liskov Substitution
Liskov’un Yerine Geçme
Liskov Substitution
Alt sınıflardan oluşturulan nesneler, üst sınıflardan oluşturulan nesnelerle yer değiştirdiklerinde aynı davranışı sergilemek zorundadırlar.
class Employee
{
protected $baseSalary = 2000;
public function getSalary()
{
throw new EmployeException('This employee salary is not defined yet.');
}
}
class Engineer extends Employee
{
public function getSalary()
{
return $this->baseSalary * 3
}
}
class Manager extends Employee
{
public function getSalary()
{
return $this->baseSalary * 5;
}
}
class Intern extends Employee {}
class SalaryCalculator
{
public function getTotalSalary()
{
$total = 0;
foreach(getEmployeers() as $employee) {
if($employee instanceof Intern) {
$total += 0;
} else {
$total += $employee->getSalary();
}
}
return $total;
}
}
class SalaryCalculator
{
public function getTotalSalary()
{
$total = 0;
foreach(getEmployeers() as $employee) {
$total += $employee->getSalary();
}
return $total;
}
}
“I”Interface Segregation
Arayüz Ayırma
Interface Segregation
Birbiriyle ilişkili olmayan pek çok metodu ihtiva eden arayüzler yerine birbiriyle ilişkili metodlardan oluşan çok sayıda arayüz kullanılmalı.
interface PosInterface
{
public function preAuthorization(PreAuthorizationRequest $request);
public function postAuthorization(PostAuthorizationRequest $request);
public function sale(SaleRequest $request);
public function refund(RefundRequest $request);
public function cancel(CancelRequest $request);
public function processProviderResponse(ProviderResponse $providerResponse);
public function finalize(Finalize3dRequest $request);
}
class SynchPayA implements PosInterface
{
/...
}
class SynchPayB implements PosInterface
{
/...
}
interface PosInterface
{
public function sale(SaleRequest $request);
public function refund(RefundRequest $request);
public function cancel(CancelRequest $request);
}
interface ThreeDSecureAware
{
public function processProviderResponse(ProviderResponse $providerResponse);
public function finalize(Finalize3dRequest $request);
}
interface PreAuthorizationWare
{
public function preAuthorization(PreAuthorizationRequest $request);
public function postAuthorization(PostAuthorizationRequest $request);
}
class SynchPayA implements PosInterface, PreAuthorizationWare
{
/...
}
class SynchPayB implements PosInterface, PreAuthorizationWare, ThreeDSecureAware
{
/...
}
“D”Dependency Inversion
Bağımlılıkların Tersine Çevirilmesi
Dependency Inversion
Somut sınıflarla olan bağımlılıklar arayüzler ve soyut sınıflar kullanılarak kaldırılmalı.
interface CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount);
}
class StandardGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SilverGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SaleRules
{
public function calculateDiscount($rule, $totalAmount)
{
if($rule instanceof StandardGroupRule) {
/...
$discount $rule->calculateDiscount
} elseif($rule instanceof SilverGroupRule) {
/...
$discount $rule->calculateDiscount
}
return $discount
}
}
interface CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount);
}
class StandardGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SilverGroupRule implements CustomerGroupRuleInterface
{
public function calculateDiscount($totalAmount)
{
return $totalAmount * 0.95 + 3 / 2
}
}
class SaleRules
{
public function calculateDiscount(CustomerGroupRuleInterface $rule, $totalAmount)
{
return $rule->calculateDiscount($totalAmount);
}
}
http://tr.linkedin.com/in/ibrahimgunduz
https://github.com/ibrahimgunduz34
https://twitter.com/ibrahimgunduz34
http://www.ibrahimgunduz.net/
Teşekkürler