
Kode "Ilahi" adalah istilah yang kedengarannya tinggi yang mungkin tampak seperti tajuk kuning, namun demikian justru kode tersebut yang akan dibahas: bagian mana yang terdiri dari dan bagaimana cara menulisnya. Ini adalah kisah tentang upaya saya untuk memastikan bahwa tugas tidak kembali dengan ulasan kode dengan catatan: "Semua yang dia * nya - redo."
Saya tidak memiliki pendidikan khusus, dan saya harus belajar pemrograman dalam praktik, melalui kesalahan, lecet dan memar. Terus-menerus berupaya meningkatkan kualitas kode tertulis, saya menyusun beberapa aturan yang harus dipatuhi. Saya ingin membagikannya.
Kode TUHAN - akronim akronim - kode yang ditulis sesuai dengan prinsip-prinsip Grasp, Object calisthenics, hukum Demeter dan Solid. Seseorang yang mereka semua tahu, seseorang hanya bertemu beberapa, tetapi kami akan mempertimbangkan setiap komponen akronim. Saya tidak menetapkan sebagai tujuan saya untuk menyelami setiap kelompok aturan secara terperinci, karena telah dibahas berulang kali di Internet. Sebaliknya, saya menawarkan pemerasan dari pengalaman saya sendiri.
GRASP
Sembilan templat untuk menetapkan tanggung jawab ke kelas dan objek. Untuk kenyamanan mengingat, saya membaginya menjadi dua subkelompok:
- Di subkelompok pertama, kita dapat membedakan aturan yang memungkinkan Anda untuk menulis modul atom yang diuji dan dimodifikasi dengan baik. Aturan-aturan ini tidak begitu banyak tentang tanggung jawab, tetapi, katakanlah, tentang sifat-sifat modul: kopling lemah, adhesi kuat, polimorfisme, resistensi terhadap perubahan. Bagi saya sendiri, saya menimpa aturan ini dengan SOLID, lebih lanjut tentang ini di bagian yang sesuai.
- Subkelompok kedua adalah templat yang lebih jelas yang memberi tahu kami tentang siapa yang menciptakan objek ("pencipta" - nama kolektif untuk pola pabrik), cara mengurangi konektivitas antara modul (menggunakan pola "pengontrol" dan "perantara") kepada siapa untuk didelegasikan tanggung jawab individu (ahli informasi) dan apa yang harus dilakukan jika saya suka DDD dan pada saat yang sama kopling rendah (fiksi murni).
Baca lebih lanjut di
sini .
Senam objek
Seperangkat aturan eksekusi kode yang sangat mirip dengan kode undang-undang codeStyle. Ada juga sembilan dari mereka. Saya akan berbicara tentang tiga yang saya coba ikuti dalam pekerjaan sehari-hari saya (sedikit dimodifikasi), sisanya dapat dibaca dalam
sumber aslinya .
- Panjang metode tidak lebih dari 15 LOC, jumlah metode di kelas tidak lebih dari 15, jumlah kelas dalam satu ruang nama tidak lebih dari 15. Intinya adalah lembaran kode yang panjang sangat sulit dibaca dan dipahami. Selain itu, kelas panjang dan metode adalah sinyal pelanggaran SRP (lebih lanjut tentang ini di bawah).
- Maksimum satu tingkat peneluran per metode.
public function processItems(array items)
{
// 0
foreach (items as item) {
// 1
for (i = 0; i < 5; i++) {
// 2
… process item 5 times …
}
}
}
item
.
public function processItems(array items)
{
// 0
foreach (items as item) {
// 1
this.processItem(item);
}
}
public function processItem(Item item)
{
// 0
for (i = 0; i < 5; i++) {
// 1
… process item 5 times …
}
}
-, — , , . else
, .
public function processSomeDto(SomeDtoClass dto)
{
if (predicat) {
throw new Exception(‘predicat is failed’);
} else {
return this.dtoProcessor.process(dto);
}
}
:
public function processSomeDto(SomeDtoClass dto)
{
if (predicat) {
throw new Exception(‘predicat is failed’);
}
return this.dtoProcessor.process(dto);
}
, .
GRASP’a. , .

: B, . . :
- .
- , .
- .
- , .
. , .
this.objectB.objectC.getSomeStuff()
, , .
. -, . :
public function methodA()
{
spawnedObject = this.factory.spawn();
spawnedObject.performSomeStuff();
}
:
public function methodA()
{
this.factory.spawn().performSomeStuff();
}
, - .
public function methodA()
{
this.processor.process(this.factory.spawn());
}
: DTO/Entity. .
public function methodA(SomeDtoClass dto)
{
dto.getAddress().getCity();
}
, , . , , , ,
getCity DTO Address
dto
.
SOLID
SRP, OCP, LSP, ISP, DIP — , .
SRP — . — , . High Cohesion GRASP’a.
: , — - (MVC). - - , SRP.
public function indexAction(RequestInterface request): ResponseInterface
{
requestDto = this.requestTransformer.transform(request);
responseDto = this.requestProcessor.process(requestDto);
return this.responseTransformer.transform(responseDto);
}
- , , — . , , , , .
OCP — -. , , .
- , if/switch. , . . — . , .
resolver, .
final lass Resolver implements ResolverInterface
{
private mapping;
public function Resolver(array mapping)
{
this.mapping = mapping;
}
public function resolve(Item item)
{
return this.mapping[item.getType()].perform(item);
}
}
, . : , final, abstract, .
LSP — . , .
:
- ( ).
- ( , , , ).
- ( ).
- , ( , , , ).
class ParentClass
{
public function someMethod(string param1)
{
// some logic
}
}
class ChildClass extends ParentClass
{
public function someMethod(string param1, string param2)
{
if (param1 == '') {
throw new ExtraException();
}
// some logic
}
}
someMethod
ChildClass
(
param2
),
param1
, . ,
ParentClass
ChildClass
.
ISP — . , . , , , , — , .
interface DuckInterface
{
public function swim(): void;
public function fly(): void;
}
class MallardDuck implements DuckInterface
{
public function swim(): void
{
// some logic
}
public function fly(): void
{
// some logic
}
}
class RubberDuck implements DuckInterface
{
public function swim(): void
{
// some logic
}
public function fly(): void
{
// can't fly :(
}
}
RubberDuck
DuckInterface
. , , ,
DuckInterface
FlyableInterface
SwimableInterface
, .
DIP — . , , ( , ).
new
.
class DIPViolation
{
public function badMethod()
{
someService = new SomeService(445, 'second params');
// operations with someService
}
}
- , . . :
class DIP
{
private $service;
public function DIP(SomeServiceInterface $someService)
{
$this->someService = $someService;
}
public function goodMethod()
{
// operations with someService
}
}
, , , , «» . , . , , , «», , :)