Kode itu hidup dan mati. Bagian Satu Benda-benda

Kode adalah pemikiran. Sebuah tugas muncul, dan pengembang berpikir bagaimana menyelesaikannya, bagaimana mengekspresikan persyaratan dalam fungsi dan kelas, bagaimana menjadikan mereka teman, bagaimana mencapai ketelitian dan kebenaran, dan bagaimana membuat bisnis dengan benar. Praktik, teknik, prinsip, pola dan pendekatan - semuanya perlu diperhitungkan dan semuanya perlu diingat.


Dan seiring dengan ini, kita melihat epidemi yang meluas dari manajer, pembantu, layanan, pengontrol, penyeleksi, adapter, getter, setter dan roh jahat lainnya: semua ini adalah kode mati. Dia belenggu dan berantakan.


Saya mengusulkan pertempuran dengan cara ini: Anda perlu menyajikan program sebagai teks dalam bahasa alami dan mengevaluasinya. Bagaimana ini dan apa yang terjadi - dalam artikel.


Siklus daftar isi


  1. Benda-benda
  2. Tindakan dan properti
  3. Kode sebagai teks

Prolog


Pengalaman saya sederhana (sekitar empat tahun), tetapi semakin saya bekerja, semakin saya mengerti: jika program tidak dapat dibaca, tidak ada artinya di dalamnya. Sudah lama dikenal dan dipukuli untuk mengingatkan - kode tidak hanya memecahkan beberapa masalah sekarang , tetapi juga nanti : didukung, diperluas, diperbaiki. Selain itu, ia selalu: membaca.


Bagaimanapun, ini adalah teks.


Estetika kode sebagai teks adalah tema utama dalam siklus. Estetika di sini adalah gelas yang melaluinya kita melihat sesuatu dan berkata, ya, itu bagus, ya, itu indah.


Dalam hal kecantikan dan kelengkapan, kata-kata sangat penting. Untuk mengatakan: "Saat ini, persepsi saya dalam keadaan kusam karena tingginya kadar etanol dalam darah" sama sekali tidak sama dengan: "Saya mabuk . "


Kami adalah program yang beruntung hampir seluruhnya terdiri dari kata-kata.


Katakanlah Anda perlu membuat "karakter yang memiliki kesehatan dan mana, dia berjalan, menyerang, menggunakan mantra," dan Anda dapat langsung melihat: ada objek (karakter, kesehatan, mana, mantra), tindakan (berjalan, serang, gunakan) dan properti ( karakter memiliki health, mana, speed of casting spell) - semua ini akan menjadi nama: kelas, fungsi, metode, variabel, properti dan bidang, dalam satu kata, semua yang dipecah menjadi bahasa pemrograman.


Tapi saya tidak akan membedakan kelas dari struktur, bidang dari properti, dan metode dari fungsi: karakter sebagai bagian dari narasi tidak tergantung pada detail teknis (bahwa itu dapat direpresentasikan baik sebagai referensi atau tipe signifikan). Suatu hal yang pada dasarnya berbeda: bahwa ini adalah karakter dan bahwa mereka memanggilnya Hero (atau Character ), dan bukan HeroData atau HeroUtils .


Sekarang saya akan mengambil segelas estetika dan menunjukkan bagaimana beberapa kode ditulis hari ini dan mengapa itu jauh dari sempurna.


Benda-benda


Dalam C # (dan tidak hanya), objek - contoh kelas yang ditempatkan di heap, tinggal di sana untuk sementara waktu, dan kemudian pengumpul sampah menghapusnya. Dapat juga dibuat struktur pada stack atau array asosiatif, atau yang lainnya. Bagi kami mereka adalah: nama kelas, kata benda.


Nama dalam kode, seperti nama pada umumnya, dapat membingungkan. Ya, dan Anda jarang melihat nama yang jelek, tetapi benda yang indah. Apalagi jika itu adalah Manager .


Manajer, bukan objek


UserService , AccountManager , DamageUtils , MathHelper , GraphicsManager , GameManager , VectorUtil .


Bukan akurasi dan tangibilitas yang mendominasi di sini, tetapi sesuatu yang kabur, meninggalkan suatu tempat dalam kabut. Untuk nama-nama seperti itu, banyak yang diizinkan.


Misalnya, di GameManager apa pun Anda dapat menambahkan apa pun yang terkait dengan game dan logika game . Enam bulan kemudian, akan muncul singularitas teknologi.


Atau, itu terjadi, Anda harus bekerja dengan facebook. Mengapa tidak meletakkan semua kode di satu tempat: FacebookManager atau FacebookService ? Kedengarannya sangat sederhana, tetapi niat yang tidak jelas menciptakan keputusan yang sama tidak jelasnya . Pada saat yang sama, kita tahu bahwa ada pengguna, teman, pesan, grup, musik, minat, dll. Di Facebook. Kata-kata yang cukup!


Tidak hanya ada kata-kata yang cukup: kita masih menggunakannya. Hanya dalam pidato biasa, bukan di antara program.


Dan itu bukan GitUtils , tetapi IRepository , ICommit , IBranch ; bukan ExcelHelper , tetapi ExcelDocument , ExcelSheet ; bukan GoogleDocsService , tetapi GoogleDocs .


Setiap area subjek diisi dengan objek. "Benda-benda itu ditandai oleh kekosongan besar" , "Jantung berdetak kencang" , "Rumah itu berdiri" - benda-benda bertindak, mereka merasa, mereka mudah untuk membayangkan; mereka ada di suatu tempat di sini, berwujud dan padat.


Pada saat yang sama, Anda kadang-kadang melihat ini: di repositori Microsoft/calculator - CalculatorManager dengan metode: SetPrimaryDisplay , MaxDigitsReached , SetParentDisplayText , OnHistoryItemAdded ...


(Tetap saja, saya ingat pernah melihat UtilsManager ...)


Itu terjadi seperti ini: Saya ingin memperluas tipe List<> dengan perilaku baru, dan ListUtils atau ListHelper dilahirkan. Dalam hal ini, lebih baik dan lebih akurat untuk hanya menggunakan metode ekstensi - ListExtensions : mereka adalah bagian dari konsep, dan bukan dump dari prosedur.


Salah satu dari beberapa pengecualian adalah OfficeManager sebagai pos.


Selebihnya ... Program tidak boleh dikompilasi jika mengandung kata-kata seperti itu.


Aksi bukannya objek


IProcessor , ILoader , ISelector , IFilter , IProvider , ISetter , ICreator , IOpener , IHandler ; IEnableable , IInitializable , IUpdatable , ICloneable , IDrawable , ILoadable , IOpenable , ISettable , IConvertible .


Di sini, esensi esensi adalah prosedur, bukan konsep, dan kode lagi kehilangan citra dan keterbacaannya, dan kata yang biasa digantikan oleh yang buatan.


Lebih hidup adalah ISequence , bukan IEnumerable ; IBlueprint , bukan ICreator ; IButton , bukan IButtonPainter ; IPredicate , bukan IFilter ; IOpeneable , bukan IOpeneable ; IToggle , bukan IEnableable .


Sebuah cerita yang bagus menceritakan tentang karakter dan perkembangannya, dan bukan tentang bagaimana pencipta menciptakan, pembangun membangun dan menggambar pelukis. Suatu tindakan tidak dapat sepenuhnya mewakili suatu objek. ListSorter bukan SortedList .


Ambil DirectoryCleaner , misalnya, objek yang membersihkan folder pada sistem file. Apakah itu elegan? Tetapi kami tidak pernah mengatakan: "Minta pembersih folder untuk membersihkan D: / Test" , selalu: "Clean D: / Test" , sehingga Directory dengan metode Clean terlihat lebih alami dan lebih dekat.


Kasus yang lebih hidup lebih menarik: FileSystemWatcher dari .NET adalah perubahan pelaporan pengamat sistem file. Tetapi mengapa seluruh pengamat, jika perubahan itu sendiri dapat melaporkan bahwa mereka terjadi? Selain itu, mereka harus terkait erat dengan file atau folder, sehingga mereka juga harus ditempatkan di Directory atau File (menggunakan properti Changes dengan kemampuan untuk memanggil file.Changes.OnNext(action) ).


Nama-nama verbal seperti itu tampaknya membenarkan pola desain Strategy , menginstruksikan untuk "merangkum keluarga algoritma" . Tetapi jika alih-alih "keluarga algoritma" kita menemukan objek otentik yang ada dalam cerita, kita akan melihat bahwa strategi itu hanyalah generalisasi.


Untuk menjelaskan ini dan banyak kesalahan lainnya, kita beralih ke filosofi.


Keberadaan mendahului esensi


MethodInfo , ItemData , AttackOutput , CreationStrategy , StringBuilder , SomethingWrapper , LogBehaviour .


Nama-nama seperti itu disatukan oleh satu hal: keberadaan mereka didasarkan pada keterangan.


Itu terjadi bahwa sesuatu mengganggu dengan cepat tugas: ada sesuatu yang hilang atau ada, tetapi bukan sesuatu. Kemudian Anda berpikir: "Suatu hal yang dapat melakukan X sekarang akan membantu saya" - ini adalah bagaimana keberadaan dipahami. Kemudian, untuk "melakukan" X, XImpl ditulis - ini adalah bagaimana entitas muncul.


Oleh karena itu, alih-alih IArrayItem , IIndexedItem atau IItemWithIndex lebih umum, atau, katakanlah, di API Refleksi, daripada metode ( Method ), kita hanya melihat informasi tentang itu ( MethodInfo ).


Cara yang lebih benar: dihadapkan dengan kebutuhan akan keberadaan, temukan entitas yang mengimplementasikannya, dan, karena inilah sifatnya, yang lain.


Sebagai contoh, mereka ingin mengubah nilai tipe string tanpa membuat instance menengah - itu ternyata menjadi solusi langsung dalam bentuk StringBuilder , sedangkan, menurut saya, itu lebih tepat - MutableString .


Ingat sistem file: DirectoryRenamer tidak diperlukan untuk mengganti nama folder, karena begitu Anda menyetujui keberadaan objek Directory , tindakan sudah ada di dalamnya, Anda hanya belum menemukan metode yang sesuai dalam kode.


Jika Anda ingin menjelaskan cara mengambil kunci , maka tidak perlu mengklarifikasi bahwa ini adalah ILockBehaviour atau ILockStrategy , yang jauh lebih mudah - ILock (dengan metode Acquire yang mengembalikan IDisposable ) atau ICriticalSection (dengan Enter ).


Ini juga mencakup semua jenis Data , Info , Output , Input , Args , Params (lebih jarang State ) - objek yang sama sekali tidak memiliki perilaku, karena mereka dianggap sepihak.


Di mana keberadaannya adalah primer, hasil bagi dicampur dengan jenderal, dan nama-nama objek membingungkan - Anda harus membaca setiap baris dan mencari tahu ke mana karakter pergi dan mengapa hanya ada Data .


Taksonomi Aneh


CalculatorImpl , AbstractHero , ConcreteThing , CharacterBase .


Semua untuk alasan yang sama dijelaskan di atas, kita kadang-kadang melihat objek yang tempat dalam hierarki ditunjukkan dengan tepat. Sekali lagi, keberadaan bergegas ke depan, sekali lagi kita melihat bagaimana kebutuhan mendesak dengan cepat tumpah ke dalam kode, tanpa mempertimbangkan konsekuensinya.


Lagipula, apakah benar ada seseorang ( Human ) - pewaris dari orang dasar ( HumanBase )? Tapi bagaimana ketika Item mewarisi AbstractItem ?


Terkadang mereka ingin menunjukkan bahwa tidak ada Character , tetapi semacam kesamaan "mentah" - CharacterRaw .


Impl , Abstract , Custom , Base , Concrete , Internal , Raw - tanda ketidakstabilan, ketidakjelasan arsitektur, yang, seperti pistol dari adegan pertama, pasti akan menembak nanti.


Pengulangan


Dengan tipe bersarang, ini terjadi: RepositoryItem di Repository , WindowState di Window , HeroBuilder in Hero .


Pengulangan memotong makna, memperburuk kelemahan, dan hanya berkontribusi pada kompleksitas teks.


Bagian yang berlebihan


Untuk menyinkronkan utas, ManualResetEvent sering digunakan dengan API berikut:


 public class ManualResetEvent { //   —  `EventWaitHandle`. void Set(); void Reset(); bool WaitOne(); } 

Setiap kali, secara pribadi, saya harus ingat bagaimana Set berbeda dari Reset (tata bahasa yang tidak nyaman) dan apa yang dimaksud dengan "acara reset manual" secara umum dalam konteks bekerja dengan stream.


Dalam kasus seperti itu, lebih mudah untuk menggunakan metafora yang jauh dari pemrograman (tetapi dekat dengan kehidupan sehari-hari):


 public class ThreadGate { void Open(); void Close(); bool WaitForOpen(); } 

Pasti tidak ada yang membingungkan!


Kadang-kadang muncul ke konyol: tentukan bahwa item bukan hanya Items , tetapi tentu saja ItemsList atau ItemsDictionary !


Namun, jika ItemsList tidak lucu, maka AbstractInterceptorDrivenBeanDefinitionDecorator dari Spring ItemsList - ItemsList . Kata-kata dalam nama ini adalah kain dari mana monster raksasa dijahit. Meskipun ... Jika ini adalah monster, lalu apa yang terjadi dengan HasThisTypePatternTriedToSneakInSomeGenericOrParameterizedTypePatternMatchingStuffAnywhereVisitor ? Harapan warisan .


Selain nama kelas dan antarmuka, orang sering menemukan redundansi dalam variabel atau bidang.


Misalnya, bidang tipe IOrdersRepository disebut _ordersRepository . Tetapi seberapa pentingkah melaporkan bahwa pesanan dikirimkan oleh repositori? Lagi pula, jauh lebih mudah - _orders .


Itu juga terjadi bahwa dalam kueri LINQ mereka menulis nama argumen penuh ekspresi lambda, misalnya, Player.Items.Where(item => item.IsWeapon) , meskipun kami sudah memahami item ini dengan melihat Player.Items . Dalam kasus seperti itu, saya ingin selalu menggunakan karakter yang sama - x : Player.Items.Where(x => x.IsWeapon) (dengan kelanjutan ke y , z jika ini adalah fungsi di dalam fungsi).


Total


Saya akui, dengan permulaan seperti itu tidak akan mudah untuk menemukan kebenaran objektif. Seseorang, misalnya, akan mengatakan: menulis Service atau tidak menulis adalah poin yang diperdebatkan, tidak penting, rasanya enak, dan apa bedanya jika itu berfungsi?


Tapi Anda bisa minum dari gelas sekali pakai!


Saya yakin bahwa jalan menuju konten terletak melalui formulir, dan jika seseorang tidak melihat pemikiran itu, tampaknya sudah hilang. Dalam teks program, semuanya bekerja dengan cara yang sama: gaya, suasana dan ritme membantu untuk mengekspresikan diri mereka tidak bingung, tetapi dimengerti dan luas.


Nama objek tidak hanya wajahnya, tetapi juga makhluk, diri. Ini menentukan apakah itu akan halus atau jenuh, abstrak atau nyata, kering atau animasi. Namanya berubah - konten berubah.


Pada artikel selanjutnya kita akan membahas tentang konten ini dan apa yang terjadi.

Source: https://habr.com/ru/post/id447404/


All Articles