The Power of Refactoring

Project yang sedang dikerjakan sekarang adalah membuat Mobil App untuk membaca score (notasi musik) dengan beberapa fitur seperti pengaturan tempo, looping, environment, change instrument, adding annotation dan sebagainya. Masalahnya kemudian,hampir semua developer yang terlibat adalah backend programmer yang tidak punya pengalaman mengerjakan mobile app dan juga tidak familiar menggunakan pattern MVVM. Ya, projectnya menggunakan Xamarin dan MvvmCross framewrok.

Nah, pada sprint kesekian project pengerjaan projectnya semakin melambat. Salah satu penyebabnya adalah beberapa task mengharuskan menunggu pengerjaan developer yang lain karena mengharuskan bekerja pada class/module yang sama. Begitu juga bagian FrontEnd mengaku kesulitan dalam mengintegrasikan designnya karena harus bersentuhan dengan code program yang berhubungan dengan funcionality.

Akhirnya diputuskan dalam satu sprint di adakan refactor besar-besaran, tidak ada penambahan fitur. Refacor focus pada aspek Single Responsibility dan Separation of Concern. Juga melengkapi unit testing sehingga dapat dengan mudah dideteksi mana code yang termasuk smell code. Ya, salah satu tandanya adalah jika code tersebut tidak testable. Ternyata setelah mengadakan refactor yang cukup signifikan, Sprint berikutnya pekerjaan menjadi lebih mudah dan cepat.

Error When Call IMvxCommand in Unit Testing

Kode unit testing di bawah ini ketika memanggil SampleClickCommand menyebabkan error Null Object Reference.

[TestMethod]
       public void WhenPlayClick_SampleMusicIsPlaying()
       {
           _mockAudioService.Setup(arg => arg.PlayMusic(It.IsAny<string>()));
           _mockAudioService.Setup(arg => arg.IsMusicPlaying).Returns(true);
           _scoreLibraryCellViewModel = new ScoreLibraryCellViewModel(_mockAudioService.Object, _mockFileAccessService.Object, _mockDialogService.Object);
           _scoreLibraryCellViewModel.SampleClickCommand.Execute();
 
 
 
       }

Untuk meresolve error ini register type untuk IMvxStringToTypeParser saat initialisasi.

var ioc = MvxSimpleIoCContainer.Initialize();
          ioc.RegisterSingleton<IMvxStringToTypeParser>(new MvxStringToTypeParser());

 

How to update ObservableCollection in MvvmCross when property of Item is changes

Ketika develop android app menggunakan Xamarin. Saya menggunakan MvvmCross sebagai framework. Dalam MvvM patterna kita akan selalu berurusan dengan Binding data antara View(UI)- dan ViewModel.

Saat saya melakukan binding data ObservableColletion pada ViewModel dengan ListView pada View ternyata event Collection Changes pada ObservableCollection tidak di rise ketika ada perubahan pada property di itemnya. Jadi setelah saya baca-baca, event Collection Changes ini hanya di rise ketika ada penambahan atau pengurangan jumlah item pada ObservableCollection.

Layout View.

 
 

ViewModel:

ProductListItemViewModel:

public class ProductListItemViewModel : MvxViewModel
   {
       
       public int Id { get; set; }
 
       public string Name { get; set; }
 
       private decimal _quantity;
 
       
       public decimal Quantity
       {
           get
           {
               return _quantity;
 
           }
           set
           {
               _quantity = value;
               RaisePropertyChanged(() => Quantity);
               
           }
       }

ProductListViewModel.

private ObservableCollection _displayedProducts;
       public ObservableCollection DisplayedProducts
       {
           get { return _displayedProducts; }
           set
           {
               _displayedProducts = value;
               RaisePropertyChanged(() => DisplayedProducts);
               Calculate();
           }
       }
       private void Calculate()
       {
           decimal totalSales = 0;
           decimal totalGst = 0;
           foreach (var product in DisplayedProducts)
           {
               var sales = (product.Price * product.Quantity);
               totalSales += sales;
               if (product.GstFlag)
               {
                   totalGst += sales * Utility.Constants.GST_RATE;
               }
           }
           TotalSales = totalSales;
           TotalGst = totalGst;
       }
       private decimal _totalSales;
       public Decimal TotalSales
       {
           get
           {
               
               return _totalSales;
           }
           set
           {
               _totalSales = value;
               RaisePropertyChanged(() => TotalSales);
           }
           
       }
       private decimal _totalGst;
       public Decimal TotalGst
       {
           get
           {
 
               return _totalGst;
           }
           set
           {
               _totalGst = value;
               RaisePropertyChanged(() => TotalGst);
           }
 
       }

Karena saya ingin ketika ada perubahan quantity pada Product (inputnya ditrigger dari editable text field pada listview), calculate() method dipanggil lagi sehingga property TotalSales dan TotalGst akan diupdate otomatis.

Saya menemukan solusinya dengan menset event PropertyChanges pada ProductListItemViewModel sebelum menambahkannya pada ObservableCollection seperti ini.

productViewItemModel.PropertyChanged += ProductViewItemModel_PropertyChanged;
               productViewModels.Add(productViewItemModel);
private void ProductViewItemModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Calculate();
        }

code lengkapnya ada di https://github.com/adnansetiawan/sales-app-xamarin

Builder Pattern

Jika kita memiliki sebuah class dengan banyak argument pada konstruktornya, kita bisa mempertimbangkan menggunakan Builder Pattern. Sebagai contoh

 

public Employee(string name, string carName, int paySheet, int carPrice, int saving, decimal monthlySaving,
           ITaxPaymentService taxPaymentService)
       {
           _name = name;
           _carName = carName;
           _paySheet = paySheet;
           _carPrice = carPrice;
           _saving = saving;
           _monthlySaving = monthlySaving;
           _taxPaymentService = taxPaymentService;
 
       }

kita bisa membuat sebuah class builder seperti ini.

 

public class EmployeeParam
   {
       
       public string Name { get; private set; }
       public int CarPrice { get; private set; }
       public string CarName { get; private set; }
       public int Saving { get; private set; }
       public decimal MonthySaving { get; private set; }
       public int PaySheet { get; private set; }
 
       public class Builder
       {
           private string _name;
           private int _carPrice;
           private string _carName;
           private decimal _monthySaving;
           private int _paySheet;
           private int _saving;
 
           public Builder WithName(string value)
           {
               _name = value;
               return this;
           }
 
           public Builder WithCarName(string value)
           {
               _carName = value;
               return this;
           }
 
           public Builder WithCarPrice(int value)
           {
               _carPrice = value;
               return this;
           }
 
           public Builder WithPaySheet(int value)
           {
               _paySheet = value;
               return this;
           }
 
           public Builder WithSaving(int value)
           {
               _saving = value;
               return this;
           }
 
           public Builder WithMonthlySaving(int value)
           {
               _monthySaving = value;
               return this;
           }
 
           public EmployeeParam Build()
           {
               return new EmployeeParam
               {
                   Name = _name,
                   CarName = _carName,
                   CarPrice = _carPrice,
                   MonthySaving = _monthySaving,
                   PaySheet = _paySheet,
                   Saving = _saving
               };
           }
       }
   }

 

Sekarang kita bisa memanggil class Employee dengan lebih readable seperti ini.

 

var richManBuilder = new EmployeeParam.Builder()
              .WithName("Rikki")
              .WithCarName("BMW")
              .WithPaySheet(40000000)
              .WithCarPrice(400000000)
              .WithSaving(120000000)
              .WithMonthlySaving(15000000)
              .Build();

 

Employee = new Employee(richManBuilder, _taxPaymentService);