Menggunakan objek bisnis dalam model tampilan

11

Saat menggunakan objek bisnis yang dapat digunakan kembali, praktik apa yang dianggap terbaik saat membangun model tampilan?

Kami menggunakan objek yang kami sebut Builderuntuk membangun model tampilan kami. Satu pembangun untuk setiap unit tampilan logis (pesanan, pengguna, dll), di mana setiap unit dapat berisi sejumlah model tampilan yang berbeda (pesanan berisi ringkasan, baris pesanan, dll).

Pembangun dapat menarik data melalui satu atau lebih objek bisnis standar untuk membangun model tampilan.

Apa yang dianggap praktik yang lebih baik ketika menggunakan objek / model bisnis dalam model tampilan?

Pendekatan 1

Izinkan penggunaan objek bisnis dalam model tampilan?

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary();
        obModel.Order = obOrder;

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public Some.Business.Logic.Order Order;
    //Other methods for additional logic based on the order
    //and other properties
}

Pendekatan 2

Ambil hanya data yang diperlukan dari objek bisnis

//Business object in some library
public class Order
{
    public int OrderNum;
    public int NumOrderLines;
    //...
}

//Order builder in website
public class OrderBuilder
{
    public OrderSummary BuildSummaryForOrder(int OrderNum)
    {
        Some.Business.Logic.Order obOrder = Some.Business.Logic.GetOrder(OrderNum);
        //Any exception handling, additional logic, or whatever

        OrderSummary obModel = new OrderSummary()
        {
            OrderNum = obOrder.OrderNum,
            NumOrderLnes = obOrder.NumOrderLines,
        }

        return obModel;
    }
}

//View model
public class OrderSummary
{
    public int OrderNum;
    public int NumOrderLines
    //Other methods for additional logic based on the order
    //and other properties
}

Saya bisa melihat manfaat dan kekurangannya, tetapi saya ingin tahu apakah ada pendekatan yang diterima? Dalam pendekatan 1, tidak ada duplikasi kode di sekitar model, tetapi itu menciptakan ketergantungan pada logika bisnis. Dalam pendekatan 2, Anda hanya mengambil data yang diperlukan untuk tampilan, tetapi Anda menduplikasi kode di sekitar model.

Andy Hunt
sumber

Jawaban:

12

Opsi 1 menciptakan hubungan yang erat antara model domain dan tampilan. Ini bertentangan dengan model tampilan masalah yang dirancang untuk dipecahkan.

Model tampilan "alasan untuk berubah" adalah jika tampilan itu sendiri berubah. Dengan meletakkan objek model domain dalam model tampilan, Anda memperkenalkan alasan lain untuk berubah (mis. Domain berubah). Ini adalah indikasi yang jelas tentang pelanggaran prinsip tanggung jawab tunggal. Memiliki dua atau lebih alasan untuk berubah mengarah ke model tampilan yang memerlukan banyak perawatan - mungkin lebih dari biaya pemeliharaan yang dirasakan dari duplikasi di seluruh model domain / tampilan.

Saya akan selalu menganjurkan pendekatan 2. Ini sering terjadi bahwa model tampilan mungkin terlihat sangat mirip, bahkan identik dengan objek model domain, tetapi perbedaan seperti yang saya sebutkan adalah alasan mereka berbeda untuk perubahan.

MattDavey
sumber
Apakah saya benar dalam berpikir bahwa dengan "alasan untuk mengubah" yang Anda maksud adalah perubahan dalam arti pemeliharaan, bukan perubahan dalam pengertian pembaruan (misalnya acara ui)?
Andy Hunt
@AndyBursh ya itu benar - lihat artikel ini , khususnya baris "Robert C. Martin mendefinisikan tanggung jawab sebagai alasan untuk berubah, dan menyimpulkan bahwa kelas atau modul harus memiliki satu, dan hanya satu, alasan untuk berubah."
MattDavey
Saya suka jawaban Anda tetapi beberapa pemikiran ... Model tampilan tidak selalu berubah hanya karena modelnya berubah. Hanya jika Anda mengikat atau menggunakan properti tertentu yang berubah maka ini akan menjadi masalah karena referensi Anda adalah ke seluruh objek. Memiliki referensi ke objek domain membuatnya lebih mudah untuk membuat perubahan dan menyimpannya lagi. Metode penyimpanan Anda juga bergantung pada objek domain sehingga Anda harus mengonversi model tampilan kembali atau mengatur metode bisnis Anda untuk menerima model tampilan yang juga tidak bagus. Saya masih berpikir # 2 paling masuk akal, tetapi hanya dengan dua sen.
KingOfHypocrites
Jika Anda tidak dapat memiliki objek domain di VM, lalu bagaimana Anda akan mewakili sesuatu yang lebih rumit seperti array Pesanan?
Jeff
Jadi apakah ini berarti hal-hal seperti, katakanlah, memformat timestamp untuk tampilan pengguna, harus menjadi milik lapisan tampilan, bukan lapisan domain, dan objek tingkat domain harus mengembalikan hanya stempel waktu mentah dan belum diformat ke objek tampilan dan yang terakhir adalah apa yang harus mengandung logika formatter?
The_Sympathizer
2

Opsi 1 lebih disukai karena menghindari duplikasi kode. Itu dia.

Jika model domain berubah secara signifikan, hampir pasti bahwa pandangan harus tetap berubah. Dengan opsi 2, maka Anda harus mengubah model tampilan DAN pembangun serta tampilan itu sendiri. Hal semacam itu adalah racun mutlak untuk pemeliharaan. YAGNI.

Tujuan memiliki model tampilan terpisah adalah untuk menjaga status yang bermakna hanya untuk tampilan (mis. Tab apa yang saat ini dipilih) terpisah dari model bisnis. Tetapi data bisnis itu sendiri harus digunakan kembali daripada digandakan.

Michael Borgwardt
sumber
YAGNI - pembunuh rahasia yang memecahkan sebagian besar masalah desain perangkat lunak.
Martin Blore
6
Maaf, tapi ini saran yang mengerikan untuk semua kecuali aplikasi yang paling sepele. Lihat model tidak memiliki status. Mereka adalah objek transfer data. Tab apa yang dipilih adalah bagian dari STRUKTUR tampilan dan tidak ada hubungannya dengan DATA dalam model tampilan apa pun. Pemeliharaan bukan mimpi buruk jika Anda menyusun program Anda dengan benar dan menggunakan sesuatu seperti Automapper untuk membuat model tampilan Anda menjadi terhidrasi.
Lucifer Sam
"Jika model domain berubah secara signifikan, hampir pasti bahwa pandangan itu harus berubah pula." - Sepakat. Tetapi bagaimana dengan ketika Anda memiliki perubahan kecil ke domain? Dengan opsi satu, setiap perubahan kecil ke domain (bahkan hanya mengubah nama properti) memerlukan perubahan yang sesuai dengan tampilan. Ini juga racun mutlak untuk perawatan.
MattDavey
@MattDavey: jika Anda mengubah nama properti maka dengan model tampilan terpisah Anda juga harus mengubah tampilan (atau peta apa pun antara domain dan model tampilan) dan sekarang memiliki dua nama berbeda untuk hal yang sama, yang pasti dapat menyebabkan kebingungan.
Michael Borgwardt
@Lucifer Sam: jelas kami memiliki konsep yang sangat berbeda tentang apa model tampilan. Anda kedengarannya sangat, sangat aneh bagi saya, seperti Anda menggambarkan aplikasi mainframe untuk terminal bodoh, tetapi tentu saja bukan aplikasi web atau klien lemak modern.
Michael Borgwardt
2

Prinsip dan mantra terkadang berharga untuk memandu desain ... tapi inilah jawaban praktis saya:

Bayangkan model tampilan Anda diserialisasi ke JSON atau XML. Jika Anda mencoba dan membuat serial model domain Anda, Anda akan berakhir dengan kekacauan teks yang mengerikan dan kemungkinan besar akan mengalami masalah dengan referensi melingkar dan masalah lainnya.

Tujuan dari model tampilan bukan untuk mengelompokkan model domain bersama sehingga tampilan dapat mengkonsumsinya. Sebaliknya model tampilan harus menjadi model tampilan yang benar-benar datar ... hal yang sebenarnya Anda lihat di layar. Logika tampilan Anda hanya harus berkaitan dengan penataan data yang ada dalam model tampilan.

Idealnya model tampilan Anda harus terdiri hampir seluruhnya dari string pra-diformat. Pikirkan tentang hal ini ... Anda bahkan tidak ingin DateTime atau desimal dalam model tampilan Anda karena Anda terjebak melakukan pemformatan logika dalam C #, Javascript, Objective-C, dll.

Lucifer Sam
sumber
2
Saya tidak pernah memiliki masalah dengan model domain serialisasi. Dan mengubah segalanya menjadi string dalam model? Serius?
Michael Borgwardt
3
@MichaelBorgwardt Ya, ini yang seharusnya menjadi model tampilan. Anda tidak ingin membuat serialisasi model domain Anda dan mengirimkannya ke semua tempat. Semua logika bisnis harus tetap aman di rumah di satu tempat. Namun tampilan harus fleksibel dan dapat ditampilkan pada perangkat apa pun yang mengapa Anda ingin memisahkan STRUKTUR, DATA, dan GAYA Anda sepenuhnya.
Lucifer Sam
Maaf, tapi ITULAH nasihat yang mengerikan untuk aplikasi apa pun, titik. Ini mengarah ke aplikasi rekayasa ulang penuh kode duplikat yang merupakan kebalikan dari fleksibel.
Michael Borgwardt
1
@MichaelBorgwardt sepertinya Anda terbiasa bekerja dengan model domain anemia di mana entitas sedikit lebih dari tas properti dengan sedikit atau tanpa perilaku. Dalam hal itu ya, model DTO / Tampilan pada dasarnya akan menjadi duplikat. Namun, jika Anda memiliki model domain yang kaya dengan hubungan yang kompleks, lapisan DTOs / View-model menjadi perlu, dan mereka tidak akan begitu mirip dengan entitas domain.
MattDavey
@MattDavey: Kedengarannya seperti model domain yang Anda gunakan untuk bekerja tidak hanya kaya tetapi benar-benar kleptokrat. Saya juga tidak suka model anemia, tetapi mereka masih model, dan perilaku mereka harus dibatasi untuk mewakili domain. Prinsip tanggung jawab tunggal dan semua itu ...
Michael Borgwardt