Apa itu "abstraksi prematur"?


10

Saya pernah mendengar frasa dilemparkan ke seluruh penjuru dan bagi saya argumennya terdengar sangat gila (maaf jika saya sedang bermain di sini, ini bukan maksud saya), umumnya berbunyi seperti:

Anda tidak ingin membuat abstraksi sebelum Anda tahu apa masalahnya secara umum, jika tidak (1) Anda mungkin meletakkan sesuatu di abstraksi yang bukan milik Anda, atau (2) menghilangkan hal-hal penting.

(1) Bagi saya ini terdengar seperti programmer tidak cukup pragmatis, mereka telah membuat asumsi bahwa hal-hal akan ada di program akhir yang tidak, sehingga mereka bekerja dengan rendahnya level abstraksi, masalahnya tidak abstraksi prematur, itu konkret prematur.

(2) Menghilangkan hal-hal penting adalah satu hal, sangat mungkin ada sesuatu yang dihilangkan dari spek yang kemudian ternyata menjadi penting, solusi untuk ini bukan dengan menghasilkan sumber daya limbah dan limbah Anda sendiri ketika Anda mengetahui bahwa Anda Dugaan salah, itu untuk mendapatkan lebih banyak informasi dari klien.

Kita harus selalu bekerja dari abstraksi ke konkret karena ini adalah cara yang paling pragmatis dalam melakukan sesuatu, dan bukan sebaliknya.

Jika kita tidak melakukannya maka kita berisiko salah paham klien dan menciptakan hal-hal yang perlu diubah, tetapi jika kita hanya membangun abstraksi yang didefinisikan klien dalam bahasa mereka sendiri, kita tidak pernah mengenai risiko ini (setidaknya jauh dari kemungkinan mengambil suntikan dalam kegelapan dengan beberapa pertimbangan), ya itu mungkin klien berubah pikiran tentang detail, tetapi abstraksi yang mereka gunakan pada awalnya berkomunikasi apa yang mereka inginkan cenderung masih valid.

Berikut ini sebuah contoh, katakanlah klien ingin Anda membuat robot mengantongi item:

public abstract class BaggingRobot() {
    private Collection<Item> items;

    public abstract void bag(Item item);
}

Kami sedang membangun sesuatu dari abstraksi yang digunakan klien tanpa lebih detail dengan hal-hal yang tidak kami ketahui. Ini sangat fleksibel, saya telah melihat ini disebut "abstraksi prematur" ketika pada kenyataannya akan lebih prematur untuk mengasumsikan bagaimana bagging diimplementasikan, katakanlah setelah berdiskusi dengan klien mereka ingin lebih dari satu item dikantong sekaligus . Untuk memperbarui kelas saya, saya hanya perlu mengganti tanda tangan, tetapi untuk seseorang yang memulai dari bawah ke atas yang mungkin melibatkan perbaikan sistem yang besar.

Tidak ada yang namanya abstraksi prematur, hanya konkret prematur. Apa yang salah dengan pernyataan ini? Di mana kelemahan dalam alasan saya? Terima kasih.


1
Kebalikan dari abstraksi prematur adalah YAGNI - Kamu Tidak Akan Membutuhkannya, yang menurut saya hampir selalu salah. Hampir. Saya sudah melihat itu terjadi, tetapi jarang. Saya sebagian besar setuju dengan apa yang Anda katakan di sini.
user1118321

Jawaban:


19

Setidaknya menurut saya, abstraksi prematur cukup umum, dan terutama sangat awal dalam sejarah OOP.

Setidaknya dari apa yang saya lihat, masalah utama yang muncul adalah orang membaca contoh-contoh khas hierarki berorientasi objek. Mereka mendapat banyak informasi tentang menyiapkan segala sesuatunya untuk menghadapi perubahan di masa depan yang mungkin muncul (meskipun tidak ada alasan khusus yang kuat untuk percaya bahwa mereka akan melakukannya). Tema lain yang umum pada banyak artikel untuk sementara waktu adalah hal-hal seperti platipus, yang menentang aturan sederhana tentang "mamalia semua seperti ini" atau "semua burung seperti itu."

Akibatnya, kami berakhir dengan kode yang benar-benar hanya perlu untuk menangani, katakanlah, catatan karyawan, tetapi ditulis dengan hati-hati untuk siap jika Anda pernah menyewa arakhnida atau mungkin krustasea.


Jadi abstraksi prematur bukanlah tindakan abstraksi, melainkan abstraksi yang melampaui tingkat spesifikasi abstraksi. Itu jauh lebih masuk akal, dan saya bisa melihat itu benar-benar terjadi. Saya kira saya hanya perlu menjelaskan kepada kolega saya bahwa saya bekerja pada tingkat abstraksi yang digariskan oleh manajer saya.
James

1
@James: ini juga bisa berarti abstrak "terlalu banyak" karena spesifikasi versi 1.0, karena Anda yakin Anda mengetahui persyaratan baru dalam spesifikasi versi yang lebih baru, oleh karena itu sudah mengimplementasikan v1.0 dengan cara yang lebih umum daripada perlu. Kadang-kadang, baik untuk membayangkan apa yang mungkin terjadi dalam versi yang lebih baru, tetapi ada juga risiko overengineering.
Doc Brown

@DocBrown Saya akan menyebutnya konkresi prematur. Tindakan abstraksi adalah menghapus informasi, bukan menambahkannya. Jika Anda menambahkan lebih banyak ke abstraksi daripada yang diperlukan maka Anda mengasumsikan sesuatu tentang abstraksi tingkat yang lebih rendah. Saya ingin membedakan antara keduanya karena saya pikir menyebut bahwa "abstraksi" tidak masuk akal karena definisi abstraksi adalah "proses mengekstraksi esensi yang mendasarinya" Di mana ketika konkresi "ditandai dengan atau dimiliki oleh pengalaman langsung dari hal atau peristiwa aktual ".
James

6

Penting untuk diingat bahwa abstraksi adalah sarana untuk mencapai tujuan. Anda menggunakan abstraksi untuk menyamakan perilaku di seluruh program Anda dan membuat penambahan kelas baru secara langsung dalam kasus di mana Anda mengharapkan kelas baru ditambahkan tetapi hanya ketika abstraksi diperlukan pada saat itu.

Anda tidak akan menambahkan abstraksi hanya karena Anda mungkin membutuhkannya (tanpa dasar nyata untuk berpikir Anda perlu menambahkan kelas baru di masa depan). Metafora yang tepat di sini mungkin pipa. Mudah-mudahan Anda akan setuju bahwa pipa 6 arah yang memungkinkan air mengalir naik / turun, timur / barat, utara / selatan akan menjadi jenis pipa paling fleksibel yang bisa Anda miliki. Anda secara teoritis bisa menggunakan pipa 6-arah di mana saja pipa diperlukan, dan memblokir arah yang tidak dibutuhkan, kan?

Jika Anda mencoba untuk memperbaiki masalah dengan kebocoran di bawah wastafel Anda dan menemukan semua bagian pipa adalah potongan pipa 6-arah, Anda ingin menarik rambut keluar dengan frustrasi pada pria yang mendesainnya seperti itu. Anda tidak hanya tidak tahu di mana masalahnya, tetapi hampir pasti akan lebih mudah untuk memulai dari awal dengan cara yang tepat.

Tentu saja pengkodean tidak ledeng, tetapi metafornya masih berlaku. Abstraksi seperti menggunakan potongan pipa 6 arah itu. Gunakan mereka ketika Anda benar-benar percaya Anda mungkin satu hari dalam waktu dekat kebutuhan untuk menghubungkan pipa dari semua 6 arah. Kalau tidak, abstraksi hanyalah komplikasi, tidak jauh berbeda dari menggunakan pola di mana tidak ada yang diperlukan atau menggunakan kelas dewa yang berusaha melakukan semuanya. Jika tidak digunakan, dan kemungkinan tidak akan pernah digunakan, Anda akhirnya menambahkan kelas tambahan tanpa biaya.

Diakui, seni menulis program sangat sangat abstrak secara konseptual. Cukup layak untuk disebutkan bahwa abstraksi tidak ada demi menjadi abstraksi tetapi karena mereka praktis dalam beberapa cara nyata. Jika Anda merasa perlu menggunakan abstraksi, ya, tapi jangan minta saya untuk memeriksa pipa ledeng Anda setelahnya. ;)


Anda tampaknya sedikit- classsentris ... Bahkan jika ada banyak kelas, abstraksi tidak terbatas untuk digunakan dalam / menguntungkan mereka.
Deduplicator

1
@Dupuplikator Cukup adil, tapi itu tidak mengubah poin saya. Jika abstraksi digunakan, itu harus segera bermanfaat atau itu harus menjadi perubahan yang direncanakan dalam waktu dekat. Tidak masalah bahwa kita mengacu pada kelas atau pemrograman fungsional.
Neil

3

Ketika saya belajar tentang Analisis dan Desain Berorientasi Objek, bertahun-tahun yang lalu, kami akan mulai dengan deskripsi bahasa Inggris sederhana dari sistem yang dibutuhkan pelanggan.

Melihat melalui itu, setiap kata benda (atau frase kata benda) akan dianggap sebagai kelas yang mungkin. Setiap kata kerja (atau frasa kata kerja) akan menjadi metode potensial pada kelas. Jadi "robot mengantongi" bisa jadi kelas BaggingRobot. "Buka tas" mungkin menjadi metode OpenBag.

Setelah beberapa iterasi, ini akan berubah menjadi diagram kelas.

Pada titik ini, tidak ada kelas abstrak. Pelanggan tidak menginginkan konsep abstrak robot pengemasan. Mereka menginginkan robot yang memasukkan barang-barang ke dalam tas. Semua kelas bersifat konkret dan memiliki serangkaian metode.

Kelas abstrak hanya diperkenalkan ketika menjadi jelas bahwa:

  • Ada beberapa kelas serupa yang dapat membentuk hierarki.
  • Mereka sebenarnya berbagi sesuatu yang sama, sehingga kelas dasar melakukan tujuan yang bermanfaat.

Bagi saya, "abstraksi prematur" adalah asumsi bahwa siapa pun BaggingRobot harus mewarisi dari beberapa BaseRobot, dan, lebih buruk lagi, mencoba mengembangkan seperangkat metode BaseRobotsebelum Anda bahkan tahu apa yang umum untuk semua robot.


Abstraksi tidak identik dengan kelas abstrak. Antarmuka adalah abstraksi. Saya berbicara tentang abstraksi secara umum, bukan hanya kelas abstrak. Mungkin saya bisa membuatnya lebih jelas dengan menggunakan antarmuka. Jika Anda mengembangkan sistem Anda pada lapisan abstraksi yang sama seperti klien Anda, maka kemungkinan besar Anda akan berakhir dengan beberapa kelas abstrak yang perlu diperluas karena bahasa secara alami abstrak. Bekerja lebih rendah dari itu adalah apa yang saya sebut "konkret prematur" di mana Anda secara naif berasumsi bahwa para klien memahami bagaimana sistem akan bekerja, sama seperti milik Anda.
James

Objek BaggingRobot yang menempatkan objek Item ke objek Bag sudah merupakan abstraksi dari robot bagging sungguhan yang memasukkan barang-barang ke dalam tas.
user253751

1

Kedengarannya agak seperti Anda ingin menyelesaikan masalah yang belum ada, dan bahwa Anda tidak memiliki alasan yang baik untuk mengasumsikan akan terjadi, kecuali jika Anda yakin klien salah dalam apa yang mereka minta. Jika itu masalahnya, saya akan merekomendasikan lebih banyak komunikasi daripada menerapkan solusi tebak, abstrak atau sebaliknya. Meskipun mungkin tampak tidak berbahaya jika hanya menampar "abstrak" pada definisi kelas dan merasa aman mengetahui Anda dapat memperpanjangnya nanti, Anda mungkin menemukan bahwa Anda tidak perlu melakukannya, atau Anda mungkin akan memperluasnya dengan cara yang terlalu memperumit desain ke bawah. garis, dengan mengabstraksi hal-hal yang salah.

Dengan contoh Anda, apakah Anda membayangkan bahwa itu adalah robot itu sendiri , barang - barang yang dikantongi atau metode mengantongi yang akan berubah di garis?

Abstraksi prematur benar-benar hanya berarti Anda tidak memiliki alasan yang baik untuk melakukan abstraksi dan karena abstraksi jauh dari bebas dalam banyak bahasa, Anda mungkin dikenai biaya overhead tanpa pembenaran.

Sunting Untuk menjawab beberapa poin dari OP di komentar, saya memperbarui ini untuk mengklarifikasi dan merespons dengan cara yang tidak memerlukan rantai komentar panjang saat membahas poin (1) dan (2) lebih khusus.

(1) Bagi saya ini terdengar seperti programmer tidak cukup pragmatis, mereka telah membuat asumsi bahwa hal-hal akan ada di program akhir yang tidak , sehingga mereka bekerja dengan rendahnya level abstraksi, masalahnya tidak abstraksi prematur, itu konkret prematur.

(Penekanan milikku). Dengan asumsi hal-hal akan ada dalam program akhir yang tidak persis seperti yang saya lihat dalam contoh Anda. Pelanggan meminta robot pengepak barang. Ini adalah permintaan yang sangat spesifik, jika agak kabur dalam bahasanya. Pelanggan menginginkan robot yang mengepak barang, jadi Anda menghasilkan sepasang benda

public class Item {
/* Relevant item attributes as specified by customer */
}
public class BaggingRobot {
  private Collection<Item> items;

  public void bag(Item item);
}

Model Anda sederhana dan tepat, mengikuti persyaratan yang ditetapkan oleh pelanggan tanpa menambahkan kerumitan pada solusi dan tanpa membuat asumsi bahwa pelanggan menginginkan lebih dari yang mereka minta. Jika, ketika disajikan dengan ini, mereka menjelaskan kebutuhan untuk robot untuk memiliki mekanik mengantongi dipertukarkan, hanya kemudian apakah Anda memiliki informasi yang cukup untuk membenarkan menciptakan sebuah antarmuka atau metode lain abstraksi, karena Anda dapat sekarang arahkan ke nilai tertentu yang ditambahkan ke sistem melalui abstraksi.

Sebaliknya, jika Anda memulai dengan abstraksi dari pragmatisme murni, Anda menghabiskan waktu untuk membuat antarmuka terpisah dan mengimplementasikannya dalam konkret, atau membuat kelas abstrak, atau cara abstraksi apa pun yang Anda suka. Jika ternyata pelanggan puas dengan hal ini, dan tidak perlu perpanjangan lebih lanjut, Anda telah menghabiskan waktu dan sumber daya dengan sia-sia, dan / atau memperkenalkan overhead dan kompleksitas ke dalam sistem tanpa hasil.

Berkenaan dengan (2), saya setuju bahwa menghilangkan hal-hal penting bukan merupakan ciri abstraksi prematur. Abstraksi atau tidak, Anda dapat menghilangkan sesuatu yang penting dan kecuali jika ditemukan jauh di bawah garis abstraksi, tidak akan lebih sulit atau lebih mudah untuk menyelesaikannya dengan cara apa pun.

Sebagai gantinya , saya akan menafsirkannya sebagai makna bahwa abstraksi apa pun berisiko mengaburkan model domain Anda. Abstraksi yang salah dapat membuat sistem sangat sulit untuk dipikirkan, karena Anda membuat hubungan yang secara drastis dapat mempengaruhi pertumbuhan lebih lanjut dari model domain dan pemahaman domain. Anda berisiko menghilangkan informasi yang tidak penting tentang hal yang diabstraksikan , tetapi tentang sistem secara keseluruhan , dengan membawa model Anda ke lubang kelinci yang salah.


"Kedengarannya agak seperti kamu ingin menyelesaikan masalah yang belum ada, dan bahwa kamu tidak punya alasan untuk menganggap akan terjadi, kecuali kamu hanya percaya klien salah dalam apa yang mereka minta." - Ini sama sekali bukan apa yang saya katakan, sebenarnya saya membuatnya jelas bahwa saya hanya membangun berdasarkan kata-kata yang digunakan klien. Ini adalah tindakan tidak ingin melakukan ini yang mendorong saya untuk menggunakan abstraksi.
James

"Saya akan merekomendasikan lebih banyak komunikasi daripada menerapkan solusi tebak" - Maksud Anda seperti yang saya sarankan? Mengutip apa yang saya katakan di OP "solusi untuk ini tidak datang dengan konkret Anda sendiri dan sumber daya limbah ketika Anda tahu Anda salah menebak, itu untuk mendapatkan lebih banyak informasi dari klien."
James

"Meskipun mungkin tampak tidak berbahaya untuk hanya menampar 'abstrak' pada definisi kelas dan merasa aman mengetahui Anda dapat memperluasnya nanti" - Ketika saya mengatakan "abstraksi" Maksud saya "abstraksi" Saya tidak bermaksud "kata kunci abstrak". Antarmuka bisa berupa abstraksi, abstraksi adalah logika fuzzy, itulah yang dibicarakan seluruh postingan ini. Klien berkomunikasi dalam hal abstraksi sehingga kita harus memprogram dalam istilah abstrak sampai kita tahu lebih banyak tentang domain.
James

1
"Anda mungkin menemukan bahwa Anda tidak perlu" - Ini tidak masuk akal. Seorang klien mengatakan "Saya ingin robot yang mengemas barang", Anda membuat abstraksi yang memenuhi kriteria itu. Setiap informasi lebih lanjut yang Anda dapatkan dari klien akan menjadi informasi terperinci tentang bagaimana mereka ingin pengemasan dilakukan. Ini tidak membatalkan abstraksi Anda, klien tidak tiba-tiba berubah pikiran tentang ide inti di balik apa yang mereka beli. Robot masih akan mengepak barang. Abstraksi yang Anda buat masih akan berlaku.
James

"Atau Anda mungkin mendapati diri Anda memperluasnya dengan cara yang terlalu memperumit desain, dengan mengabstraksi hal-hal yang salah." ... Apakah Anda jujur ​​membaca apa yang saya katakan atau hanya judulnya? Serius? Poin baca (1) & (2)
James
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.