Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. ASP.NET
Code

Code Generation Menggunakan T4

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Imam Firmansyah (you can also view the original English article)

Saya tidak menyukai code generation dan biasanya, saya melihatnya sebagai "bau". Jika Anda menggunakan code generation apa pun, ada peluang bagus ada yang salah dengan desain atau solusi Anda! Jadi mungkin alih-alih menulis skrip untuk menghasilkan ribuan baris kode, Anda harus mundur selangkah, berpikir tentang masalah Anda lagi dan menemukan solusi yang lebih baik. Dengan demikian, ada situasi di mana code generation dapat menjadi solusi yang baik.

Dalam posting ini, saya akan berbicara tentang pro dan kontra dari pembuatan kode dan kemudian menunjukkan kepada Anda bagaimana menggunakan template T4 templates, built-in code generation tools yang ada di Visual Studio, menggunakan contoh.

Code Generation adalah Suatu Ide yang Buruk

Saya menulis posting tentang konsep yang menurut saya adalah ide yang buruk, lebih sering daripada tidak dan itu akan menjadi tidak profesional bagi saya jika saya memberi Anda alat dan tidak memperingatkan Anda tentang bahayanya.

Yang benar adalah, code generation cukup menarik: Anda menulis beberapa baris kode dan Anda mendapatkan lebih banyak dari itu sebagai balasan yang mungkin Anda harus tulis secara manual. Jadi mudah untuk terperangkap dalam one-size-fits-all:

"Jika satu-satunya alat yang Anda miliki adalah palu, Anda cenderung melihat setiap masalah sebagai paku". A. Maslow

Tetapi code generation hampir selalu merupakan ide yang buruk. Saya merujuk Anda ke posting ini, yang menjelaskan sebagian besar masalah yang saya lihat dengan code generation. Singkatnya, hasil code generation menjadi kode yang tidak fleksibel dan sulit dipelihara.

Berikut ini beberapa contoh di mana Anda seharusnya tidak menggunakan code generation:

  • Dengan kode yang dihasilkan arsitektur terdistribusi Anda menjalankan skrip yang menghasilkan kontrak layanan dan implementasi dan secara ajaib mengubah aplikasi Anda menjadi arsitektur terdistribusi. Itu jelas salah untuk mengakui chattiness berlebihan dalam-proses panggilan yang secara dramatis melambat di atas jaringan dan kebutuhan untuk pengecualian yang tepat dan penanganan transaksi sistem terdistribusi dan sebagainya.
  • Perancang GUI Visual adalah apa yang telah digunakan oleh para pengembang Microsoft selama berabad-abad (di Windows/Web Forms dan sampai batas tertentu, aplikasi berbasis XAML) di mana mereka menyeret dan melepas widget dan elemen UI dan melihat kode UI (jelek) yang dihasilkan untuk mereka di belakang layar.
  • Naked Object sebuah pendekatan untuk pengembangan perangkat lunak di mana Anda mendefinisikan model domain Anda dan sisa aplikasi Anda, termasuk UI dan database, semua dihasilkan untuk Anda. Secara konseptual, itu sangat dekat dengan Model Driven Architecture.
  • Model Driven Architecture pendekatan untuk pengembangan perangkat lunak di mana Anda menentukan domain Anda secara detail menggunakan Platform Independence Model (PIM). Dengan menggunakan code generation, PIM kemudian diubah menjadi Platform Specific Model (PSM), yang dapat dijalankan komputer. Salah satu nilai jual utama MDA, adalah Anda menentukan PIM satu kali dan dapat menghasilkan aplikasi web atau desktop dalam berbagai bahasa pemrograman hanya dengan menekan tombol yang dapat menghasilkan kode PSM yang diinginkan.

    Banyak alat RAD (Rapid Application Development) dibuat berdasarkan ide ini: Anda menggambar model dan mengklik tombol untuk mendapatkan aplikasi yang lengkap. Beberapa alat ini akan mencoba untuk sepenuhnya menghapus pengembang dari persamaan di mana pengguna non-teknis dianggap mampu membuat perubahan yang aman untuk perangkat lunak tanpa perlu pengembang.

Saya juga akan menempatkan Pemetaan Relasional Objek dalam daftar karena beberapa ORM sangat bergantung pada pembuatan kode untuk menciptakan model persistensi dari model data konseptual atau fisik. Saya telah menggunakan beberapa alat ini dan telah mengalami sedikit rasa kesulitan untuk menyesuaikan kode yang dihasilkan. Dengan begitu, banyak pengembang tampaknya sangat menyukai mereka, jadi saya meninggalkannya (atau apakah saya ?!) ;)

Sementara beberapa "alat" ini memecahkan beberapa masalah pemrograman dan mengurangi upaya awal yang diperlukan dan biaya pengembangan perangkat lunak, ada biaya pemeliharaan tersembunyi yang sangat besar dalam menggunakan code generation, yang cepat atau lambat akan menggigit Anda dan semakin banyak dihasilkan kode yang Anda miliki, semakin banyak yang akan tersakiti.

Saya tahu bahwa banyak pengembang adalah penggemar besar code generation dan menulis skrip pembuatan kode baru setiap hari. Jika Anda berada di camp itu dan berpikir itu adalah alat yang hebat untuk banyak masalah, saya tidak akan berdebat dengan Anda. Lagi pula, posting ini bukan tentang membuktikan pembuatan kode adalah ide yang buruk.

Kadang, Hanya Terkadang, Code Generation adalah Ide yang Bagus

Meskipun sangat jarang, saya menemukan diri saya dalam situasi di mana code generation sangat cocok untuk masalah yang dihadapi dan solusi alternatif akan lebih sulit atau lebih buruk.

Berikut ini beberapa contoh di mana code generation yang mungkin cocok:

  • Anda perlu menulis banyak kode boilerplate yang mengikuti pola statis serupa. Sebelum mencoba code generation, dalam hal ini, Anda harus berpikir keras tentang masalah dan mencoba menulis kode ini dengan benar (misalnya, menggunakan pola berorientasi objek jika Anda menulis kode OO). Jika Anda telah berusaha keras dan belum menemukan solusi yang baik, maka code generation mungkin merupakan pilihan yang baik.
  • Anda sangat sering menggunakan beberapa metadata statis dari sumber daya dan mengambil data yang membutuhkan untuk menggunakan magic string (dan mungkin merupakan operasi yang mahal). Berikut beberapa contohnya:
    • Kode metadata diambil oleh refleksi: memanggil kode menggunakan refleksi membutuhkan magic string; tetapi pada waktu desain, Anda tahu apa yang Anda butuhkan, Anda dapat menggunakan code generation untuk menghasilkan artefak yang diperlukan. Dengan cara ini Anda akan menghindari menggunakan refleksi pada waktu berjalan dan / atau magic string dalam kode Anda. Contoh yang bagus dari konsep ini adalah T4MVC yang menciptakan pembantu yang diketik kuat yang menghilangkan penggunaan string literal di banyak tempat.
    • Layanan web lookup statis: esetiap sekarang dan kemudian saya menemukan layanan web yang hanya menyediakan data statis yang dapat diambil dengan menyediakan kunci, yang berakhir sebagai magic string dalam basis kode. Dalam hal ini, jika Anda dapat secara terprogram mengambil semua kunci, maka Anda dapat membuat kode kelas statis yang berisi semua kunci dan mengakses nilai string sebagai warga kelas pertama yang diketik dengan kuat dalam basis kode Anda alih-alih menggunakan magic string. Anda dapat dengan jelas membuat kelas secara manual; tetapi Anda juga harus mempertahankannya, secara manual, setiap kali data berubah. Anda kemudian dapat menggunakan kelas ini untuk memukul layanan web dan menyimpan hasilnya sehingga panggilan selanjutnya diselesaikan dari memori.

      Alternatifnya, jika diizinkan, Anda hanya bisa menghasilkan seluruh layanan dalam kode sehingga layanan pencarian tidak diperlukan saat runtime. Kedua solusi memiliki beberapa pro dan kontra, jadi pilih yang sesuai dengan kebutuhan Anda. Yang terakhir ini hanya berguna jika kunci hanya digunakan oleh aplikasi dan tidak disediakan oleh pengguna; jika cepat atau lambat akan ada waktu ketika data layanan telah diperbarui tetapi Anda belum menghasilkan kode, dan pencarian yang dimulai pengguna gagal.

    • Tabel pencarian statis: Ini sangat mirip dengan layanan web statis tetapi data tinggal di penyimpanan data dibandingkan dengan layanan web.

Seperti yang disebutkan di atas, code generation membuat kode-kode tidak fleksibel dan sulit dipelihara; jadi jika sifat masalah yang Anda selesaikan bersifat statis dan tidak memerlukan pemeliharaan yang sering, maka pembuatan kode dapat menjadi solusi yang baik!

Hanya karena masalah Anda cocok dengan salah satu kategori di atas tidak berarti code generation cocok untuknya. Anda harus tetap mencoba mengevaluasi solusi alternatif dan mempertimbangkan pilihan Anda.

Juga, jika Anda pergi untuk pembuatan kode, pastikan untuk tetap menulis tes unit. Untuk beberapa alasan, beberapa pengembang berpikir bahwa kode yang dihasilkan tidak memerlukan pengujian unit. Mungkin mereka berpikir itu dihasilkan oleh komputer dan komputer tidak membuat kesalahan! Saya pikir kode yang dihasilkan membutuhkan verifikasi otomatis yang sama (jika tidak lebih). Saya pribadi TDD generasi kode saya: saya menulis tes pertama, jalankan mereka untuk melihat apakah mereka gagal, kemudian menghasilkan kode dan melihat hasil tes.

Alat untuk mengubah Text Template

Ada code generation engine yang mengagumkan di Visual Studio disebut Text Template Transformation Toolkit (AKA, T4).

Dari MSDN:

Teks template terdiri dari bagian-bagian berikut:

  • Directives: elemen yang mengontrol cara template diproses.
  • Text blocks: konten yang disalin langsung ke output.
  • Control blocks: kode program yang memasukkan nilai variabel ke dalam teks dan mengontrol bagian teks yang bersyarat atau berulang.

Daripada berbicara tentang cara kerja T4, saya ingin menggunakan contoh nyata. Jadi di sini adalah masalah yang saya hadapi beberapa waktu lalu yang saya gunakan T4. Saya memiliki open source. NET library yang disebut Humanizer. Salah satu hal yang ingin saya berikan dalam Humanizer adalah API yang ramah bagi pengembang yang dapat bekerja dengan DateTime.

Saya mempertimbangkan beberapa variasi API dan pada akhirnya, memutuskan untuk ini:

Setelah saya tahu apa yang akan terlihat oleh API saya, saya berpikir tentang beberapa cara berbeda untuk mengatasi ini dan melebarkan beberapa solusi berorientasi objek, tetapi semuanya membutuhkan sedikit kode boilerplate dan yang tidak, tidak akan beri saya API publik bersih yang saya inginkan. Jadi saya memutuskan untuk menggunakan code generation.

Untuk setiap variasi saya membuat file T4 terpisah:

  • In.Months.tt untuk In.January dan In.FebrurayOf(<someyear>)dan seterusnya.
  • On.Days.tt untuk On.January.The4thOn.February.The(12) dan seterusnya.
  • In.SomeTimeFrom.tt untuk In.One.SecondIn.TwoSecondsFrom(<date time>)In.Three.Minutes dan seterusnya.

Di sini saya akan membahas On.DaysKode disalin di sini untuk referensi Anda:

Jika Anda memeriksa kode ini di Visual Studio atau ingin bekerja dengan T4, pastikan Anda telah menginstal Tangible T4 Editor for Visual Studio. Ini menyediakan IntelliSense, T4 Syntax-Highlighting, Advanced T4 Debugger dan T4 Transform on Build.

Kode mungkin tampak agak menakutkan di awal, tetapi itu hanya sebuah skrip yang sangat mirip dengan bahasa ASP. Setelah menyimpan, ini akan menghasilkan kelas yang disebut Ondengan 12 subclass, satu per bulan (misalnya, JanuariFebruari dll) Masing-masing dengan properti status publik yang mengembalikan hari tertentu di bulan itu. Mari kita pisahkan kode dan lihat cara kerjanya.

Directives

Directives syntax adalah sebagai berikut: <#@ DirectiveName [AttributeName = "AttributeValue"] ... #>. Anda dapat membaca lebih lanjut tentang directives disini.

Saya telah menggunakan directive berikut dalam kode:

Template

Template directive memiliki beberapa atribut yang memungkinkan Anda untuk menentukan berbagai aspek transformasi.

Jika atribut debug adalah true, file intermediate code akan berisi informasi yang memungkinkan debugger untuk mengidentifikasi posisi yang lebih akurat dalam template Anda di mana terjadi break atau pengecualian. Saya selalu meninggalkan ini sebagai true.

Output

Output directive digunakan untuk menentukan ekstensi nama file dan encoding dari file yang diubah. Di sini kita mengatur ekstensi ke .csyang berarti file yang dihasilkan akan berada di C # dan nama file akan menjadi On.Days.cs.

Assembly

Di sini kita sedang memuat System.Core sehingga kita dapat menggunakannya dalam blok kode lebih jauh.

The Assembly directive memuat sebuah assembly sehingga kode template Anda dapat menggunakan jenisnya. Efeknya mirip dengan menambahkan referensi assembly dalam proyek Visual Studio.

Ini berarti Anda dapat memanfaatkan sepenuhnya kerangka .NET di template T4 Anda. Misalnya, Anda dapat menggunakan ADO.NET untuk memakai database, membaca beberapa data dari tabel dan menggunakannya untuk code generation.

Lebih jauh, saya memiliki baris berikut:

Ini agak menarik. Dalam template On.Days.tt Saya menggunakan metode Ordinalize dari Humanizer yang mengubah angka menjadi string ordinal, digunakan untuk menunjukkan posisi dalam urutan yang diurutkan seperti 1, 2, 3, 4. Ini digunakan untuk menghasilkan The1stThe2nd dan seterusnya.

Dari artikel MSDN:

Nama sebuah assembly harus menjadi salah satu dari yang berikut:

  • Nama kuat dari sebuah assembly di GAC, seperti System.Xml.dll. Anda juga dapat menggunakan formulir panjang, seperti nama = "System.Xml, Versi = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089". Untuk informasi lebih lanjut, lihat AssemblyName.
  • Path absolut dari sebuah assembly.

System.Core ada di GAC, jadi kita bisa dengan mudah menggunakan namanya; tetapi untuk Humanizer kita harus menyediakan path absolut. Jelas saya tidak ingin hardcode di local path saya, jadi saya menggunakan $(SolutionDir) yang digantikan oleh sebuah solusi yang ada selama code generation. Dengan cara ini, code generation berfungsi dengan baik untuk semua orang, di mana pun mereka menyimpan kode.

Import

Import directive memungkinkan Anda untuk merujuk ke elemen di namespace lain tanpa memberikan nama yang sepenuhnya memenuhi syarat. Ini setara dengan using pernyataan penggunaan dalam C# atau import dalam Visual Basic.

Di bagian atas kita mendefinisikan semua ruang nama yang kita butuhkan di code block. Import block yang Anda lihat sebagian besar disisipkan oleh T4 Tangible. Satu-satunya hal yang saya tambahkan adalah:

Jadi saya nanti bisa menulis:

Tanpa pernyataan import dan menentukan assembly assembly dan menentukan assembly dengan path, bukan file C#, saya akan mendapatkan kesalahan kompilasi yang memberi tahu tentang tidak menemukan metode Ordinalize pada integer.

Text Blocks

Text Blocks menyisipkan teks langsung ke file output. Di bagian atas, saya telah menulis beberapa baris kode C# yang langsung disalin ke file yang dihasilkan:

Lebih jauh ke bawah, di antara control block, saya memiliki beberapa text block lain untuk dokumentasi API, metode dan juga untuk menutup sebuah kurung.

Control Blocks

Control block adalah bagian dari kode program yang digunakan untuk mengubah template. Bahasa defaultnya adalah C#.

Catatan: Bahasa tempat Anda menulis kode di control block tidak terkait dengan bahasa teks yang dihasilkan.

Ada tiga jenis control block yang berbeda: Standard, Expression, dan Class Feature.

Dari MSDN:

  • <# Standard control blocks #> dapat berisi pernyataan.
  • <#= Expression control blocks #> dapat berisi ekspresi.
  • <#+ Class feature control blocks #> dapat berisi metode, bidang dan properti.

Mari kita lihat control block yang kita miliki dalam contoh template:

Bagi saya pribadi, hal yang paling membingungkan tentang T4 adalah cara control block membuka dan menutup, karena mereka agak tercampur dengan tanda kurung di text block (jika Anda membuat kode untuk bahasa kurung siku seperti pada C #). Saya menemukan cara termudah untuk menangani ini, adalah menutup (#>) blok kontrol segera setelah saya membuka (<#) dan kemudian menulis kode di dalamnya.

Di bagian atas, di dalam standard control block, saya mendefinisikan leapYear sebagai nilai konstan. Ini agar saya dapat menghasilkan entri untuk 29 Februari Lalu saya mengulang lebih dari 12 bulan untuk setiap bulan mendapatkan firstDayOfMonth dan monthName. Saya kemudian menutup control block untuk menulis text block untuk kelas bulan dan dokumentasi XML-nya. monthName digunakan sebagai nama kelas dan dalam komentar XML (menggunakan expression block control). Sisanya adalah kode C # biasa yang tidak akan saya lakukan.

Kesimpulan

Dalam posting ini saya berbicara tentang code generation, memberikan beberapa contoh ketika code generation dapat menjadi berbahaya atau berguna dan juga menunjukkan bagaimana Anda dapat menggunakan template T4 untuk menghasilkan kode dari Visual Studio menggunakan contoh asli.

Jika Anda ingin mempelajari lebih lanjut tentang T4, Anda dapat menemukan banyak konten bagus di blog Oleg Sych.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.