#customerview
Explore tagged Tumblr posts
cloudanalytixus · 2 years ago
Text
Tumblr media
360-degree customer view data model-Cloud Analytix
0 notes
perfectfacesnl · 5 years ago
Photo
Tumblr media
May we ask for your review of our products? Here's a guide of how it can be done. Log on to: www.perfectfaces.eu #customerreviews #coronavírus #quarantinereviews #stuckinside #parabenfreemakeuprocks #ecofriendlymakeup #perfectfaces #reviewguide #customerview #darskin #blackandbeautiful (bij Amsterdam-Noord) https://www.instagram.com/p/B_CP_0HDhyr/?igshid=116gk2aigv2u1
0 notes
fashionveda-blog · 7 years ago
Photo
Tumblr media
@fabulous.designer - We customise all kind of ladies wear for girls only. Know price please Dm or WhatsApp us. For inconvenience please contact us +91 9408378997 We are shipping international. #fabulouscustomerreview #fabulousdesigner #fabulouscollection #FDstudio #happycustomer #customer #outfitreview #onlinereview #quality #orderonline #onlinestore #boutique #designetear #designergown #fashion #style #instagood #setisfaction #customerview #fdreview For inconvenience DM or WHATSAPP +91 9408378997 #fashionveda
0 notes
keeks2yuphone-blog · 7 years ago
Video
#CustomerCam ♥️👕 @noey.x got her package from us . . . #KeesTees #ShopNow #Sale #Shop #CustomerView
0 notes
phulkor · 2 years ago
Video
youtube
Victor Rentea is a reference in implementing the clean architecture. I've referenced it a few time on this blog. This time we'll focus on abused DTOs
Tumblr media
A DTO can be "abused" if it is used in a way that goes beyond its intended purpose. For example, if a DTO is used to transfer data from a database to a user interface, it may be fine to include database-specific fields such as a primary key in the DTO. However, if the same DTO is then used to transfer data between business layers or to other systems, those database-specific fields may no longer be relevant and could cause confusion or errors.
Another way a DTO can be abused is when it is used to transfer data between layers without a proper mapping strategy. A common mistake is that the DTO and the entity have the same fields. As the system evolves they will not be in sync and can cause issues.
An example of a correctly implemented DTO in Java might be:
class UserDTO { private String firstName; private String lastName; private String email; // Getters and setters for each field }
An example of an abused DTO in Java might be:
class UserDTO { private int id; // database primary key private String firstName; private String lastName; private String email; private boolean isAdmin; // business logic flag // Getters and setters for each field }
In the example above, the id field is specific to the database and the isAdmin field is specific to the business logic. Both of these fields may not be relevant or appropriate when transferring data between layers or systems, and could cause confusion or errors.
Victor goes on to explain in the example that CustomerView should have a field CustomerCommonDto and not extend from it.
Finally be weary that when doing this you might end up DRY-ing code on the assumption of fragile coincidence!
More about this in another entry.
Happy coding!
0 notes
intensetechnologies · 3 years ago
Photo
Tumblr media
To serve the necessities of tech-savvy #customers, the #banking, #telecom, and #insurance sectors need to go through a paradigm shift. The prolonged #customeronboarding process, lack of a single unified #customerview, and manual paper-driven processes are conquered with UniServe™ NXT. #technology #datamodeling #tech #businessandmanagement #digitaltransformation #innovation #ai #cx #customerexperiencestrategy #informationtechnology #ccm
0 notes
alifgiant · 5 years ago
Text
Perbedaan Sederhana dari MVC, MVP, MVVM dan MVI
Kita pasti sudah tidak asing dengan architecture design pattern yang saya sebutkan di judul (MVC, MVP, MVVM dan MVI). Semuanya mengajarkan mengenai bagaimana sebaiknya kita memisahkan code base kita agar mencapai konsep single responsibility (S) dari SOLID principle. Tentu saja penggunaan pattern tidak hanya terbatas disitu, tapi hal tersebut adalah yang paling jelas terlihat. Karena yang semulanya semua fungsionalitas berada dalam 1 objek, kini harus dipisahkan menjadi setidaknya 3 objek lain Model, View, dan Controller/Presenter/ViewModel/Intent.
Walaupun pattern ini sangat populer dan banyak sekali artikel yang membahasnya, tapi masih banyak yang kesulitan menjelaskan perbedaan antara ke-empatnya. Oleh karena itu saya akan mencoba menjelaskan hal tersebut melalui tulisan kali ini.
Model dan View
Kedua objek ini terdapat di semua pattern dan saya rasa sudah sangat jelas, sehingga tidak perlu saya ulangi penjelasannya... Tapi, demi kelengkapan artikel, mari saya coba jelaskan sekali lagi (alibi aja, emang mau ditulis 😜).
Model adalah objek yang merepresentasikan data yang akan ditampilkan oleh view. Sedangkan View adalah objek yang merepresentasikan apa saja interaksi yang dapat diterima/dilakukan oleh user dari/kepada sistem. View tidak melulu terkait tampilan yang dilihat di layar, untuk sistem yang lebih general, view bisa berupa daftar fungsi yang menerima input ataupun memberikan output.
Sebagai contoh, misal pada sistem pengaksesan data dari database. POJO (Plain Old Java Object) adalah Model, Database Driver (seperti Room, SqlHelper, ORM, dll) adalah Controller, dan kelas DatabaseHelper yang kalian buat untuk membungkus controller adalah View. Untuk lebih jelas silahkan lihat potongan code dibawah.
/** * Profile adalah Model * SqlHelper adalah Controller * DatabaseHelper adalah View */ class DatabaseHelper { val database = SqlHelper("mysql://192.168.0.10", "root", "root") fun openDatabase() { database.open() } fun closeDatabase() { database.close() } fun getUserProfile(id: String): Profile { val rawData = database.query(id) return parse(rawData) } }
Sekilas akan timbul pertanyaan kenapa perlu ada DatabaseHelper? Kan bisa langsung ke SqlHelper. Peryataan yang tepat, hal itu karena kita sedang menginspeksi scope database access saja. Code diatas memungkinkan kita mengganti ganti database tanpa perlu user dari DatabaseHelper mengetahuinya. Untuk scope yang lebih besar DatabaseHelper bisa dikategorikan sebagai controller, yang mana user sistem tersebut tidak perlu tau jika sewaktu waktu DatabaseHelper diganti menjadi ApiHelper.
Kalau kalian mencoba mengganti nama DatabaseHelper menjadi DatabaseView akan terdengar sangat rancu. Terlebih, karena objek DatabaseHelper hampir selalu digunakan oleh sistem yag lebih besar. Oleh karena itu pattern MVC sangat jarang, bahkan tidak pernah, digunakan untuk menggambarkan sistem selain yang memiliki tampilan.
Perbedaan Controller, Presenter, ViewModel, dan Intent.
Controller
Pada MVC, View merupakan "bos besar" dalam sistem ia pemilik dari 2 objek lainnya. Ibaratkan dalam sebuah kantor seorang bos mempekerjakan seorang OB. Bos tersebut menyuruh OB untuk membuatkan kopi. Lantas ia pergi ke toko membeli kopi bubuk, lalu kembali ke kantor, membuat kopi, lalu mengantarkannya kepada si bos. Si OB, "uang" dan kopi tersebut ya "milik" si bos (walaupun tentu saja OB bisa memiliki resource dia sendiri, misal sepeda motor). Dalam code digambarkan sebagai berikut.
/** * Money dan Coffee adalah Model * ShopController adalah Si OB "Controller" * ConsumerView adalah Si Bos "View" */ class CustomerView { var coffee = EmptyCoffeeCup() val shopper = ShopController() // si OB val person = PersonController() // otak si Bos fun onDrinkCoffeeClick() { val money = person.getMoney(15000) coffee = shopper.makeCoffee(money) person.consume(coffee) // coffee.volume -= 5 (minum dikit2) } }
Bisa dilihat dari code diatas sebuah view dapat memiliki banyak model dan banyak controller. Seperti layaknya seorang "bos". Permasalahan yang muncul adalah sistem yang tidak responsif. Hal ini karena MVC berfokus pada syncronous proses, menunggu adalah suatu hal yang wajar. Potongan code diatas akan membuat proses menunggu setiap eksekusi sampai selesai sebelum melanjutkan ke eksekusi berikutnya. Hal tersebut membuat tampilan seolah "freeze", atau tidak bergerak ketika sebuah eksekusi membutuhkan waktu yang lama. Hal ini dapat diakali dengan diperkenalkannya sistem callback dan thread. Potongan code tersebut dapat diubah menjadi seperti dibawah.
fun onDrinkCoffeeClick() { val money = person.getMoney(15000) shopper.makeCoffee( money, onCoffeeReady: (coffee) { person.consume(coffee) // coffee.volume -= 5 (minum dikit2) } ) }
Tapi bagaimana kalau ternyata getMoney juga lama? Karena person perlu ngambil uang dulu ke bank. Dan juga bagaimana kalau consume coffee juga lama? Karena dia menunggu dingin dulu? Selamat datang di Callback Hell 😈.
fun onDrinkCoffeeClick() { person.getMoney( 15000, onMoneyReady: (money) { shopper.makeCoffee( money, onCoffeeReady: (coffee) { person.consume( coffee, onCold: () { coffee.volume -= 5 } ) } ) } ) }
Presenter
Pada MVP, View dan Presenter memiliki kedudukan yang hampir setara. Mereka bisa saling menyuruh. Hanya saja, resource "model" ialah milik presenter yang mana ia yang memutuskan akan memberikan model apa kepada View. Relasi keduanya lebih kepada badan terhadap otak. Badan mengirim impuls ke otak, otak memprosesnya lalu mengirim balik impuls kepada otot badan. Contoh code diatas kini dapat diubah menjadi seperti berikut.
/** * Money dan Coffee adalah Model * CustomerPresenter adalah Otak "Presenter" * ConsumerView adalah Badan "View" */ class CustomerView { val presenter = CustomerPresenter() fun onStart() { presenter.start(this) } fun onDestroy() { presenter.stop() } fun onDrinkCoffeeClick() { presnter.drinkCoffee() } fun showDrinkAnimation() { ThreadUtils.scheduleMainThread { // open mouth, pick cup, etc.. } } } class CustomerPresenter() { lateinit var view: CustomerView? var coffee = EmptyCoffeeCup() val wallet = Wallet.get() val coffeeShop = ShopRepository() // coffee seller fun start(view: CustomerView) { this.view = view } fun stop() { this.view = null } fun makeCoffee() { val money = wallet.getMoney(15000) coffee = coffeeShop.buy(money) } fun drinkCoffee() { ThreadUtils.start { if (coffee is EmptyCoffeeCup) { makeCoffee() } coffee.volume -= 5 view?.showDrinkAnimation() } } }
Bisa dilihat diatas View dan Presenter saling memiliki reference terhadap satu sama lain. Sehingga bisa saling "menyuruh" yang mana walaupun sama-sama memanfaatkan threading tapi MVP menyelamatkan dari callback hell.
Namun masalah lain dapat timbul dari MVP yaitu MemoryLeak. MemoryLeak terjadi ketika view sudah berhenti digunakan namun presenter.stop() lupa dipanggil atau tidak terpanggil. Circular reference antara View dan Presenter akan membuat Garbage Collector (GC) tidak dapat meng-collect memori dari kedua object tersebut karena reference count nya masih belum 0. Hal ini dapat di hindari dengan menggunakan WeakReference (mengizinkan GC untuk melakukan pemutusan reference) terhadap view di presenter. Menjadi seperti berikut.
class CustomerPresenter() { lateinit var weakView: WeakReference ... fun start(view: CustomerView) { this.weakView = WeakReference(view) } ... fun drinkCoffee() { ... weakView.get()?.showDrinkAnimation() ... } }
ViewModel
Pada MVVM, VM berusaha menggabungkan kelebihan C dan P. VM tidak memiliki reference kepada View dan View tidak perlu menunggu proses pada VM tanpa terjebak ke callback hell. VM mempergunakan Observer Pattern kepada Model, dimana View melakukan observe (pengamatan terus menerus) kepada model sehingga jika terjadi perubahan maka ia akan tau. Relasi View kepada VM bisa diibaratkan seperti sutradara dan aktor. Sutradara bisa memerintah aktor melakukan sesuatu, tapi tidak sebaliknya. Sementara aktor menjalankan peran, sutradara terus menerus memperhatikan segala macam gerak dan membuat penyesuaian terhadap penempatan kamera. Mari kini kita coba refactor code sebelumnya.
/** * Money dan Coffee adalah Model * CustomerViewModel adalah Aktor "ViewModel" * CustomerView adalah Sutradara "View" */ class CustomerView { val vm = CustomerViewModel() fun onStart() { registerModel(vm) vm.scene.observeOnMainThread { currentScene -> if (currentScene == "drinking") { showDrinkAnimation() } } } fun onDrinkCoffeeClick() { vm.drinkCoffee() } fun showDrinkAnimation() { // open mouth, pick cup, etc.. } } class CustomerViewModel() { val scene = Observable() var coffee = EmptyCoffeeCup() val wallet = Wallet.get() val coffeeShop = ShopRepository() // coffee seller fun makeCoffee() { val money = wallet.getMoney(15000) coffee = coffeeShop.buy(money) } fun drinkCoffee() { ThreadUtils.start { if (coffee is EmptyCoffeeCup) { makeCoffee() } coffee.volume -= 5 scene.update("drinking") } } }
Bisa dilihat diatas tidak ada circular reference dan tidak ada callback hell. Akhirnya.. semuanya aman. Oh tidak secepat itu ferguso 🤭, "terus menurus" dalam code itu perlu di-define. Jika terus menerus itu artinya mengschedule tiap n detik atau n milidetik. Maka sistem akan tidak responsif (ketika perubahan terjadi maka update perlu menunggu schedule berikutnya) dan juga akan boros computing resource dari mesin. Karena akan banyak pengecekan yang tidak menemukan perubahan.
Oleh karena itu sebenarnya observable itu memegang reference kepada observernya. Dimana ketika value-nya berubah maka ia akan memberitahu kepada semua observernya, yang mana berarti potensi memory leak. Observable bisa menghindari Memory leak dengan menerapkan reference berupa WeakReference (lihat section sebelumnya) atau menerapkan mekanisme yang menjamin pemutusan reference ketika view akan di destroy, seperti yang dilakukan oleh LiveData di Android. Oleh karena itu MVVM dipopulerkan oleh kemunculan Android Architecture Component.
Intent
Last but not least, Intent pada MVI. Konsep MVI sangat mirip dengan MVVM dimana bergantung kepada adanya Model yang di observe. Bedanya ialah pada Intent sebuah action jika melakukan perubahan kepada sebuah model dianggap merubah keseluruhan model. Sehingga akan mentriger semua observer atau istilah lainnya akan melakukan full render. Hal tersebut tentu saja akan boros computing resource tapi hal ini seringkali preferable demi mencapai kondisi single source of truth. Sehingga menjamin tidak ada perubahan yang tidak terefleksi kepada tampilan. Misalnya contoh berikut.
var height = 172 var weight = 78 val bmiObservable = Observable(height/weight) bmiObservable.observe { bmi -> setText(bmi) } ... fun onUpdateHeightTextField(t: String) { height = t.toDouble() }
Ketika user memanggil fungsi onUpdateHeightTextField maka nilai bmiObservable tidak akan mentriger observer untuk melakukan setText. Sehingga solusi untuk permasalah diatas ialah membuat semua data menjadi observable seperti berikut.
val height = Observable(172) val weight = Observable(78) val bmiObservable = Observable(height/weight) height.observe { h -> bmiObservable.update(h/weight.value) } weight.observe { w -> bmiObservable.update(height.value/w) } ... bmiObservable.observe { bmi -> setText(bmi) } ... fun onUpdateHeightTextField(t: String) { height.update(t.toDouble()) }
Tapi solusi diatas membuat kita perlu mengganti semua data menjadi observable dan menambah banyak observer bantuan untuk sekedar mengupdate observer utama. Oleh karena itu dibuatlah solusi lebih elegan seperti berikut.
/** * State adalah Model */ class State ( val height: Double, val weight: Double ) class Intent { val state = Observable(State()) fun updateHeight(t: Double) { val newState = state.copyWith(height: t) state.update(newState) } } class View { val intent = Intent() fun onStart() { intent.state.observeOnMainThread { newState -> render(newState) } } fun render(state: State) { // do all view update base on state } fun onUpdateHeightTextField(t: String) { intent.updateHeight(t.toDouble()) } }
jika tidak menyukai immutable data, bisa juga menjadi..
class State ( var height: Double, var weight: Double ) class Intent { val state = Observable(State()) fun onUpdateHeightTextField(t: String) { state.value.height = t.toDouble() render() } fun render() { state.update(state.value) } }
solusi penulisan yang kedua membuat kita memiliki kontrol kapan ingin melakukan render. Sehingga bisa membatasi render hanya ketika diperlukan namun tetap reflect terhadap semua data.
Perlu diperhatikan juga, baik MVP, MVVM dan MVI juga tidak membatasi jumlah P, VM maupun I nya. Walaupun sering kali hanya ada 1.
Kesimpulan
Semua pattern memiliki kelebihan dan kekurangan masing-masing. Pemilihan pattern tergantung sesuai preferensi setiap coder, or at least preferensi kantor tempat coder bekerja 😂. Secara pribadi saya lebih menyukai MVI karena secara penulisan lebih sederhana dan menjamin tidak ada data yang tidak reflect walaupun dengan cost komputasi yang lebih besar. Namun kebetulan saya bekerja membuat aplikasi yang mana kemampuan komputasi walapun limited, semakin lama semakin bertambah cepat (Android dan iOS) sehingga beban komputasi yang tinggi tidak lagi signifikan. Walaupun dalam kondisi tertentu, saya bisa mengkombinasi penggunaan partialRender jika butuh melakukan optimasi.
Cukup sekian artikel kali ini. Semoga bermanfaat. Sampai ketemu di artikel berikutnya. Ciao~~
0 notes
myfundaz-blog · 6 years ago
Photo
Tumblr media
Customer Trends – You Need To Know... #NewTrends #OnlineBusiness#Ecommerce #CustomerView https://bit.ly/2JbmU7D
0 notes
cokerscupcakes · 7 years ago
Video
instagram
#customerview ...... Look at those yummy layers of Oreo Sponge & Vanilla Buttercream with crushed Oreo pieces😋😋 . . . . #cokerscupcakes #cake #cokerscakes #oreocake #oreos #birthdaycake #buttercream #buttercreamcake
0 notes
ameyostylez · 9 years ago
Photo
Tumblr media
#CustomerView 💎👑 #earrings #jewelry #order #specialdelivery 🎀www.ameyostylez.com🎀
0 notes
keeks2yuphone-blog · 7 years ago
Video
#CustomerCam 😉♥️ Our customer in Canada is loving his 2XL #TrueLove tee from #KeesTees 👕 Sizes go up to 5XL 📏 #ShopNow #Sale #Shop #CustomerView
0 notes
everprettyintl · 10 years ago
Video
instagram
Heyyyyyyy here comes more beautiful pics from #everpretty #customerview 💕Check this short video below💁 Plz feel free to tag ur friends who will love this below☺️
0 notes
keeks2yuphone-blog · 7 years ago
Photo
Tumblr media
Our customers in #Canada #NewYork and #Florida all rocking #KeesTees #TooJamaicanForThisWeather ♥️👕 #WorldwideShipping & #RushShipping available! The sale continues until February 1st ♥️ Click the link in my bio to #Shop now ( https://teespring.com/stores/kees-tees/?pr=KEESTEES4U ) #CustomerCam #CustomerView
0 notes