Tutorial Pasukan Lucee MY

Komponen sebagai perkhidmatan: susun, uji, guna

Corak perkhidmatan dalam CFML: satu komponen satu tanggungjawab, pengesahan di satu tempat, ujian ringkas yang boleh dijalankan, dan kesilapan lazim.

Komponen sebagai perkhidmatan: susun, uji, guna
0
Kandungan

Komponen sebagai perkhidmatan: susun, uji, guna

Ini bahagian terakhir siri komponen. Empat bahagian sebelum ini membina asas: apa itu .cfc, kaedah dan argumen, skop variables berbanding local, dan warisan. Bahagian ini menyatukan semuanya dalam bentuk yang digunakan dalam aplikasi sebenar: komponen sebagai perkhidmatan.

Corak ini mudah disebut tetapi sukar dilakukan dengan konsisten. Bahagian tersukar bukan menulis komponen, tetapi memutuskan apa yang patut masuk ke dalamnya.

Satu komponen, satu tanggungjawab

Perkhidmatan ialah komponen yang melakukan satu kerja untuk bahagian lain aplikasi. Ia tidak mencetak HTML, tidak membaca form, dan tidak mengetahui siapa penggunanya.

Contoh di bawah mengira harga termasuk cukai. Ia menggunakan komponen Harga daripada bahagian pertama, dan menambah pengesahan.

component output="false" {
    public any function init(numeric kadarCukai = 0.06) {
        variables.kalkulator = new komponen.Harga(arguments.kadarCukai);
        return this;
    }

    public struct function kira(required numeric harga, numeric kuantiti = 1) {
        if (arguments.harga <= 0) {
            return { ok: false, ralat: "Harga mesti lebih besar daripada sifar" };
        }
        if (arguments.kuantiti < 1 || arguments.kuantiti > 99) {
            return { ok: false, ralat: "Kuantiti antara 1 hingga 99" };
        }
        var jumlah = variables.kalkulator.hargaTermasukCukai(arguments.harga * arguments.kuantiti);
        return { ok: true, jumlah: jumlah };
    }
}

Tiga keputusan penting dalam 17 baris itu:

  • Kadar cukai diterima melalui init(), bukan dibaca daripada fail konfigurasi di dalam perkhidmatan. Ini membolehkan ujian menggunakan kadar berbeza
  • Pengesahan berada di satu tempat, di awal kaedah
  • Bentuk pulangan sentiasa sama: struct dengan ok

Mengapa bukan pengendali yang mengira

Pengendali sepatutnya menyelesaikan tiga perkara sahaja: membaca input, memanggil perkhidmatan, dan memilih respons. Jika pengiraan cukai ditulis dalam pengendali, logik yang sama akan disalin ke setiap tempat yang memerlukannya, dan setiap salinan akan berkembang berbeza.

Memisahkan perkhidmatan juga bermakna kerja berjadual boleh menggunakan logik yang sama. Laporan bulanan tidak melalui pengendali, tetapi ia boleh memanggil perkhidmatan yang sama.

Menyambung perkhidmatan ke pengendali

Pengendali yang baik pendek. Ia membaca input, memanggil perkhidmatan, dan memilih respons.

public string function kira(struct params = {}) {
    var harga = val(form.harga ?: 0);
    var kuantiti = val(form.kuantiti ?: 1);
    var hasil = new app.services.HargaService(0.06).kira(harga, kuantiti);

    if (!hasil.ok) {
        cfheader(statuscode = 400);
        return hasil.ralat;
    }
    return "Jumlah: RM" & numberFormat(hasil.jumlah, "0.00");
}

Perhatikan bahawa pengendali tidak mengira apa-apa. Ia juga tidak menyemak sama ada harga negatif, kerana semakan itu milik perkhidmatan. Jika peraturan berubah, hanya satu fail berubah.

Ujian yang boleh dijalankan tanpa rangka kerja

Tidak semua projek memerlukan rangka kerja ujian. Halaman ujian kecil sudah cukup untuk menangkap kesilapan asas, dan ia boleh dijalankan pada pelayan yang sama dengan aplikasi.

svc = new komponen.perkhidmatan.HargaService(0.06);
lulus = 0; gagal = 0;
function sah(required boolean syarat, required string nama) {
    if (arguments.syarat) { lulus++; writeOutput("LULUS " & arguments.nama & chr(10)); }
    else { gagal++; writeOutput("GAGAL " & arguments.nama & chr(10)); }
}

r1 = svc.kira(100);
sah(r1.ok && r1.jumlah == 106, "100 x 1 = 106");
r2 = svc.kira(100, 3);
sah(r2.ok && r2.jumlah == 318, "100 x 3 = 318");
r3 = svc.kira(0);
sah(!r3.ok, "harga sifar ditolak");
r4 = svc.kira(50, 200);
sah(!r4.ok, "kuantiti 200 ditolak");

Output sebenar pada Lucee 7.1.1.17:

LULUS 100 x 1 = 106
LULUS 100 x 3 = 318
LULUS harga sifar ditolak
LULUS kuantiti 200 ditolak
SKOR: 4/4

Empat ujian itu meliputi dua laluan berjaya dan dua laluan gagal. Yang kedua lebih penting, kerana kesilapan paling kerap berlaku pada input tidak sah, bukan pada input normal.

Bila TestBox berbaloi

Halaman ujian di atas cukup untuk projek kecil. Apabila bilangan ujian meningkat, atau apabila anda perlu meniru kebergantungan luar, TestBox memberi struktur: describe, it, expect, dan laporan yang seragam.

Perkara yang perlu diingat: TestBox memerlukan penyediaan runner dan laluan suite yang betul. Ia bukan sekadar meletakkan fail *Spec.cfc dalam folder dan mengharapkan ia ditemui. Sediakan runner itu sebagai langkah berasingan, dan sahkan ia benar-benar menjumpai spesifikasi sebelum menulis puluhan ujian.

Untuk siri ini, ujian ringkas dipilih kerana ia boleh dijalankan terus dalam rig yang sama dengan kod, dan hasilnya boleh dibaca tanpa alat tambahan.

Suntikan kebergantungan tanpa rangka kerja

Perkhidmatan di atas menerima kadar cukai melalui init(). Itu bentuk suntikan kebergantungan yang paling ringkas, dan ia sudah cukup untuk kebanyakan kes.

Jika perkhidmatan perlu menggunakan komponen lain, hantar komponen itu sebagai argumen.

component output="false" {
    public any function init(any kalkulator) {
        variables.kalkulator = arguments.kalkulator ?: new komponen.Harga(0.06);
        return this;
    }
}

Kelebihannya jelas semasa ujian: anda boleh menghantar kalkulator palsu yang sentiasa memulangkan 100, dan menguji logik lain tanpa bergantung pada pengiraan cukai.

Kos memanggil perkhidmatan

Satu kebimbangan biasa: adakah lapisan tambahan memperlahankan permintaan?

Ujian pada rig yang sama menunjukkan 1,000 panggilan kira() mengambil 3 hingga 5 milisaat, termasuk pembinaan objek sekali di awal. Maksudnya, kos per panggilan berada dalam lingkungan mikrosaat, jauh di bawah kos pertanyaan pangkalan data atau rendering templat.

Yang mahal bukan lapisan perkhidmatan, tetapi membina perkhidmatan baharu untuk setiap baris dalam gelung, atau memanggil pangkalan data berulang kali di dalam perkhidmatan tanpa cache.

Empat kesilapan dalam corak perkhidmatan

  1. Perkhidmatan yang membaca form atau url. Ia menjadi terikat kepada satu permintaan, dan tidak boleh digunakan oleh kerja berjadual
  2. Perkhidmatan yang memulangkan HTML. Ia sepatutnya memulangkan data, bukan paparan
  3. Perkhidmatan yang menyimpan keadaan pengguna dalam variables, iaitu kesilapan yang dibincangkan dalam bahagian ketiga
  4. Perkhidmatan yang terlalu besar. Jika ia mengendalikan harga, cukai, diskaun, inventori dan e-mel, ia bukan satu tanggungjawab; ia lima

Cara memecahkan perkhidmatan yang terlalu besar

Mulakan dengan menamakan kerja yang dilakukan. Jika namanya mengandungi "dan", ia patut dipecahkan.

Perkhidmatan HargaService yang mengira jumlah, menyemak stok dan menghantar e-mel sepatutnya menjadi tiga: pengiraan harga, semakan stok, dan notifikasi. Setiap satu boleh diuji sendiri, dan setiap satu boleh berubah tanpa menjejaskan yang lain.

Pemecahan tidak perlu sempurna pada percubaan pertama. Yang penting ialah setiap perkhidmatan mempunyai satu sebab untuk berubah.

Soalan lazim

Di mana perkhidmatan sepatutnya disimpan?

Dalam folder services atau perkhidmatan di dalam aplikasi, dan diakses melalui pemetaan atau laluan relatif. Yang penting bukan nama foldernya, tetapi konsistensi: satu tempat untuk semua perkhidmatan.

Perlukah setiap perkhidmatan ada init()?

Hanya jika ia menerima kebergantungan atau konfigurasi. Perkhidmatan tanpa keadaan tidak memerlukannya.

Bolehkah pengendali memanggil beberapa perkhidmatan?

Boleh, dan selalunya perlu. Yang perlu dielakkan ialah satu perkhidmatan memanggil lima perkhidmatan lain secara tersembunyi, kerana itu menyukarkan ujian dan menyembunyikan kebergantungan.

Adakah corak ini sesuai untuk aplikasi kecil?

Ya, tetapi jangan paksakan. Jika aplikasi hanya mempunyai tiga templat dan satu jadual, perkhidmatan mungkin menambah lapisan tanpa faedah. Gunakan apabila kerja yang sama mula berulang.

Penutup siri

Lima bahagian siri ini membentuk satu laluan yang munasabah untuk dipelajari mengikut urutan:

  • Bahagian 1: apa itu .cfc, beza dengan .cfm, dan bila komponen tidak berbaloi
  • Bahagian 2: kaedah, argumen wajib dan lalai, hujah bernama, dan jenis pulangan
  • Bahagian 3: variables berbanding local, dan bagaimana data boleh bocor antara pengguna
  • Bahagian 4: extends, super, had protected dalam Lucee, dan antara muka
  • Bahagian 5, artikel ini: corak perkhidmatan, pengesahan di satu tempat, dan ujian ringkas

Jika dibaca berturutan, setiap bahagian menjawab satu soalan yang timbul daripada bahagian sebelumnya. Jika dibaca berasingan, setiap satu masih boleh digunakan sendiri, kerana kodnya lengkap dan diuji.

Bahagian pertama ada di Komponen CFML: apa itu .cfc, dan bahagian keempat di Warisan dan antara muka. Semua kod dalam siri ini diuji pada Lucee 7.1.1.17, dan setiap angka yang disebut ialah output sebenar daripada rig ujian.

Log masuk untuk menyimpan kemajuan bacaan anda.

0 komen

0 komen

Log masuk untuk menjawab atau memberi komen.

Log masuk