Archive

Monthly Archives: September 2015

.NET developers have used the [ExcludeFromCodeCoverage] attribute to focus validation on their business logic’s code coverage.

However, when building Xamarin.Forms applications, the [ExcludeFromCodeCoverage] attribute is not supported within the Portable Class Library.

To workaround this issue, use the [DebuggerNonUserCode] attribute instead. Be aware that the debugger will be disabled for the code associated to this attribute. As a result, to use the debugger, one must comment out or remove the “DebuggerNonUserCode” attribute.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net

Advertisements

Intro

It is absolutely essential to protect our code base from breaking changes. “We must protect this house!” One of the most important tests that need to be performed in software is testing user confirmations. Many professional debuggerers only know how to test this by launching the actual application to display a confirmation dialog. There is a better way of testing this part of an application. It’s called unit testing. Unit tests can not only test business logic. Unit tests can also target user-interaction logic such as confirmation dialogs. There are multiple ways to unit test a user-confirmation dialog.

One method is to use an interface that exposes an event. When the event on that interface is raised, the user-interaction logic gets invoked. I wrote an article about this implementation here. The “UserInteraction” interface can be leveraged from Bizmonger.Patterns on Nuget.

Testing with Messages

An alternative approach to unit testing a confirmation dialog without using an interface would be leveraging a Publisher/Subscribe model. Specifically, we rely on a messaging system. Using this approach, a mediator has two responsibilities. The first responsibility that the mediator has is to route the subscriptions of subscribers to their corresponding publishers. The other responsibility is to route the messages of publishers to their corresponding subscribers.

Consider the following code:

ViewModel.internal

using static Bizmonger.Patterns.MessageBus;

void Process(bool isSuccessful)
{ 
    SubscribeFirstPublication(Messages.REQUEST_CONTINUE_LOGGING_RESPONSE, OnConfirmation);
    Publish(Messages.REQUEST_CONTINUE_LOGGING, isSuccessful);
}
 
void OnConfirmation(object obj)
{
    var continueLogging = (bool)obj;
 
    if (!continueLogging) return;
 
    ContinueLogging();
}

The above logic publishes a request to continue with an operation. It is important to realize that a subscription to a response of that request must be registered first before publishing the request. I call this method of structuring code a “promise”. Hence, we promise to respond to a message.

View (Code-behind)

using static Bizmonger.Patterns.MessageBus;

public partial class View : ContentPage
{
    bool _continueLogging = false;
 
    public View()
    {
        InitializeComponent();

        Subscribe(Messages.REQUEST_CONTINUE_LOGGING, async obj =>
            {
                var status = (bool)obj ? "success" : "failure";
                _continueLogging = await DisplayAlert("Confirmation", $"Confirm {status}?", "Ok", "Cancel");
                Publish(Messages.REQUEST_CONTINUE_LOGGING_RESPONSE, _continueLogging);
            });
    }
}

The code above reflects the logic used to display a confirmation dialog. Within the constructor of our view, we subscribe to a confirmation message from the outside world. This message is “REQUEST_CONTINUE_LOGGING”. When this message comes in from the outside world, we display a confirmation dialog to our user asking if he/she would like to continue with the operation. We then publish the user’s response from the confirmation we displayed for the unknown subscribers to handle.

Unit Test

The following is a unit test that that handles the user confirmation:

[TestMethod]
public void adding_success_updates_datapoints()
{
    // Setup
    var databaseCreated = new MockDatabase() != null;
    var viewModel = new ViewModel();
 
    Subscribe(Messages.REQUEST_CONTINUE_LOGGING, obj =>
        Publish(Messages.REQUEST_CONTINUE_LOGGING_RESPONSE, true));
 
    // Test
    viewModel.Success.Execute(null);
 
    // Verify
    var datapoint = viewModel.DataPoints.Single();
    var expected = datapoint.Successes == 1 &&
                   datapoint.Failures == 0;
 
    Assert.IsTrue(expected);
}

Observe how we subscribe to a request and then publish a response.

Conclusion

In conclusion, one of the most important tests that need to be performed in software is testing user confirmations. Many professional debuggerers only know how to test this by launching the actual application to display a confirmation dialog. There is a better way of testing this part of an application. It’s called unit testing. Unit tests can not only test business logic. Unit tests can also target user-interaction logic such as confirmation dialogs. There are multiple ways to unit test a user-confirmation dialog. I have documented these methods of testing user-interactions via interfaces (aka contracts) and also by messaging.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net

Intro

I recently gave a presentation last night on constructing an application out of user story modules. I presented my thesis to an audience of mobile developers. They found the idea to be interesting but ultimately impractical. They argued that a solution could be spread so thin with granular projects that it would be overwhelming for developers to maintain the solution as it grows. I agreed with them. However, as solutions grow even without the design that I presented, they are still prone to the same concerns. The design that I presented, results in better maintainability per project.

Code Map

I informed the audience about Visual Studio’s Code Map tool and how it complements user story composed solutions. Code Maps provide visual feedback on a user story’s dependencies. Hence, using Code Map will inform reviewers of a code base on what areas of the code base a specific user story is referencing. I have found that when I use Code Map to review my code, some user stories were referencing DLLs that they shouldn’t have been. As a result, I was able to resolve that dependency which ultimately prevented unnecessary technical debt.

The following image reflects a user story module reflected by Code Map:

XamarinUserStoryModule

Single Responsibility Principle

Keep code together that tends to change together and pull code apart that tends to change for different reasons.

I don’t think this principle is limited to just methods and classes. I think it applies to all libraries. Most of us will acknowledge that a library as a utility should do one thing and do that one thing well. However, most of us do not have that same attitude regarding our client as a library. We tend to have our client by default as an executable with all views embedded within it. This results in our executable having too many dependencies than it’s really required to have.

Code Analysis

In addition to using Code Map to review code, I also run code analysis to quickly identify modules of interests that I may need to audit. Specifically, I rely on the maintainability index of a project to decide if it requires further examination.

The following image reflects the code analysis ran on my solution:

CodeMetrics

Conclusion

In conclusion, I recently gave a presentation last night on constructing an application out of user story modules. I presented my thesis to an audience of mobile developers. They found the idea to be interesting but ultimately impractical. They argued that a solution could be spread so thin with granular projects that it would be overwhelming for developers to maintain the solution as it grows. I agreed with them. However, as solutions grow even without the design that I presented, they are still prone to the same concerns. I then identified how using this type of design could result in lower maintenance cost on a per library basis determined by code analysis.

Intro

Xamarin.Forms integrates well with SQLite. It also supports WCF and some other web service frameworks. Whether we are performing CRUD operations on the local database or on a network server, we need to be professional developers and not professional debuggerers. Hence, we should unit test our business logic. This article provides some ideas to consider when unit testing operations that involve CRUD operations.

I recently wrote an app to record my success rate with meeting people:

For the app, I wrote a unit test for an Add operation:

[TestMethod]
public void adding_success_updates_datapoints()
{
    // Setup
    var databaseCreated = new MockDatabase() != null;
    var viewModel = new ViewModel();
 
    // Test
    viewModel.Success.Execute(null);
 
    // Verify
    var datapoint = viewModel.DataPoints.Single();
    var expected = datapoint.Successes == 1 &&
                   datapoint.Failures == 0;
 
    Assert.IsTrue(expected);
}

This unit test targets the view-model and tests the “Success” command that gets triggered by an app’s button press. When this command is executed an insert operation ultimately occurs on a mock database. Notice how I said “MockDatabase”. We use a mock database so that we can ensure that our business logic is correct thus enabling us to troubleshoot integration issues if and when insert operations fail.

ViewModel.commands

Our view-model command can be found here along with another command:

public partial class ViewModel
{
    void ActivateCommands()
    {
        Success = new DelegateCommand(obj => AddDataPoint(true));
        Failed = new DelegateCommand(obj => AddDataPoint(false));
    }
 
    public DelegateCommand Success { get; private set; }
    public DelegateCommand Failed { get; private set; }
}

ViewModel.internal

Our private operations and state for our view-model can be found here:

public partial class ViewModel
{
    DataPointsRepository _repository = new DataPointsRepository();
 
    void AddDataPoint(bool isSuccessful)
    {
        AddEncounter(isSuccessful);
        Refresh();
    }
 
    void AddEncounter(bool isSuccessful)
    {
        var encounter = new Encounter() { IsSuccessful = isSuccessful };
        _repository.Add(encounter);
    }
 
    void Refresh()
    {
        var datapoints = _repository.GetDataPoints();
        DataPoints = new ObservableCollection<DataPoint>(datapoints);
 
        var totalCount = DataPoints.Sum(dp => dp.Successes + dp.Failures);
        var successCount = DataPoints.Sum(dp => dp.Successes);
 
        if (totalCount == 0) return;
 
        SuccessRate = (decimal)successCount / (decimal)totalCount;
        Ratio = $"{successCount} out of {totalCount}";
    }
}

Repository

Our repository class serves as a façade for database operations. This class relies on a database interface to processes CRUD operation results for its client. The bootstrap process required involves making a promise to respond to a database instance sent to this repository object. After the promise is made, the repository sends a database request.

public partial class DataPointsRepository
    {
        public DataPointsRepository()
        {
            MakePromises();
            SendRequests();
        }
 
        public IEnumerable<Encounter> GetEncounters(DateTime date)
        {
            var compareDate = date.ToString(Constants.DATE_FORMAT);
            var result = _database.GetEncounters(compareDate);
 
            if (result == null) return new HashSet<Encounter>();
 
            return result;
        }
 
        public IEnumerable<Encounter> GetEncounters() => _database.GetEncounters();
 
        public IEnumerable<DataPoint> GetDataPoints()
        {
            _datapointDictionary.Clear();
 
            var encounters = GetEncounters();
 
            foreach (var encounter in encounters)
            {
                DataPoint foundDatapoint = null;
                var exists = _datapointDictionary.TryGetValue(encounter.Date, out foundDatapoint);
 
                if (exists)
                {
                    SetValue(encounter, foundDatapoint);
                }
                else
                {
                    var datapoint = new DataPoint(encounter.Date);
 
                    SetValue(encounter, datapoint);
                    _datapointDictionary.Add(datapoint.Date, datapoint);
                }
            }
 
            return _datapointDictionary.Values;
        }
 
        public void Add(Encounter encounter)
        {
            var encounters = GetEncounters(DateTime.Now);
            var todaysEncounters = new HashSet<Encounter>(encounters);
            todaysEncounters.Add(encounter);
 
            _dateEncounters[DateTime.Now.ToString(Constants.DATE_FORMAT)] = todaysEncounters;
 
            _database.Add(encounter);
        }
    }

Repository.internal

Repository.internal maintains internal state and sends a request for a database instance.

public partial class DataPointsRepository
{
    Dictionary<string, HashSet<Encounter>> _dateEncounters = new Dictionary<string, HashSet<Encounter>>();
    Dictionary<string, DataPoint> _datapointDictionary = new Dictionary<string, DataPoint>();
    IDatabase _database = null;
 
    void SetValue(Encounter encounter, DataPoint datapoint)
    {
        if (encounter.IsSuccessful) datapoint.Successes++;
        else datapoint.Failures++;
    }
 
    void OnRequestDatabase(object obj) => _database = obj as IDatabase;
 
    void MakePromises() =>
        Subscribe(Messages.REQUEST_DATABASE_RESPONSE, OnRequestDatabase);
 
    void BreakPromises() =>
        Unsubscribe(Messages.REQUEST_DATABASE_RESPONSE, OnRequestDatabase);
 
    void SendRequests() =>
        Publish(Messages.REQUEST_DATABASE);
}

AbstractDatabase

We use an abstract database to perform common operations that our app’s database and our unit test database require. This abstract class is leveraged so that we can support the DRY principle. Specifically, we declare abstract CRUD operations that need to be implemented from our app’s database and our unit test database. Also in this class, we implement database related subscriptions. When we receive a database request from the outside world, we publish ourselves as the response to the request.

    public abstract class AbstractDatabase : IDatabase
    {
        protected void MakePromises() =>
            Subscribe(Messages.REQUEST_DATABASE, OnRequestDatabase);
 
        protected void BreakPromises() =>
            Unsubscribe(Messages.REQUEST_DATABASE, OnRequestDatabase);
 
        protected void OnRequestDatabase(object obj) =>
            Publish(Messages.REQUEST_DATABASE_RESPONSE, this);
 
        public abstract void Add(Encounter encounter);
 
        public abstract IEnumerable<Encounter> GetEncounters();
 
        public abstract IEnumerable<Encounter> GetEncounters(string compareDate);
    }

IDatabase

In order for us to unit test our repository logic we need an interface to reflect our database operations.

public interface IDatabase
{
    IEnumerable<Encounter> GetEncounters(string compareDate);
    IEnumerable<Encounter> GetEncounters();
    void Add(Encounter encounter);
}

MockDatabase

Here’s the database used within our unit tests. Within the constructor, we make promises to respond to messages we’re interested in and we initialize our database.

public class MockDatabase : AbstractDatabase
{
    HashSet<Encounter> _dateEncounters = new HashSet<Encounter>();
 
    public MockDatabase()
    {
        MakePromises();
        InitializeData();
    }
 
    void InitializeData() { }
 
    public override void Add(Encounter encounter) => _dateEncounters.Add(encounter);
 
    public override IEnumerable<Encounter> GetEncounters() => _dateEncounters;
 
    public override IEnumerable<Encounter> GetEncounters(string compareDate) =>
        _dateEncounters.Where(dp => dp.Date == compareDate);
}

Database

Here’s the database used within the actual application. Within the constructor, we make promises to respond to messages we’re interested in and we initialize our database.

    public class Database : AbstractDatabase
    {
        SQLiteConnection _databaseConnection = null;
 
        public Database()
        {
            MakePromises();
            InitializeData();
        }
 
        void InitializeData()
        {
            _databaseConnection = DependencyService.Get<IDataConnection>().Connect();
 
            var tableExists = DependencyService.Get<IDataConnection>().TableExists(_databaseConnection, "Encounter");
 
            if (!tableExists)
            {
                _databaseConnection.CreateTable<Encounter>();
            }
        }
 
        public override IEnumerable<Encounter> GetEncounters(string compareDate) =>
            _databaseConnection.Table<Encounter>().Where(dp => dp.Date == compareDate);
 
        public override IEnumerable<Encounter> GetEncounters() => _databaseConnection.Table<Encounter>();
 
        public override void Add(Encounter encounter) =>
            _databaseConnection.Insert(encounter);
    }

In conclusion, whether we are performing CRUD operations on the local database or on a network server, we need to be professional developers and not professional debuggerers. Hence, we should unit test our business logic. This article provides some ideas to consider when unit testing operations that involve CRUD operations.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net

Intro

I recently experimented with bar charts for Xamarin.Forms. I tried to use Oxyplot, which is a popular open source tool for implementing graph charts. However, I ran into versioning issues between my Xamarin.Forms assemblies and Oxyplot. After an hour of frustration, I searched for an alternative approach. I soon found one. It was Syncfusion.

Bar Charts with Syncfusion

I got started learning about Synfusion’s support for bar charts with an awesome tutorial by James Montemagno.

I implemented the following app after reading his tutorial:

The app maintains a bar chart representation of successes and failures.

Assembly References

Make sure to add the proper assembly references described in the tutorial.

Android

lib/android/Syncfusion.SfChart.Android.dll

lib/android/Syncfusion.SfChart.XForms.dll

lib/android/Syncfusion.SfChart.XForms.Android.dll

Add new SfChartRenderer(); in the MainActivity.cs after Forms.Init (this, bundle);.

Portable Class Library lib/pcl/Syncfusion.SfChart.XForms.dll

Solution Explorer

My Solution Explorer is reflected below:

Stats_solutionExplorer

XAML

The XAML is below:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:ViewStats="clr-namespace:ViewStats;assembly=ViewStats" xmlns:chart="clr-namespace:Syncfusion.SfChart.XForms;assembly=Syncfusion.SfChart.XForms" x:Class="ViewStats.View">
 
	<ContentPage.BindingContext>
		<ViewStats:ViewModel />
	</ContentPage.BindingContext>
 
    <Grid Padding="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
 
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="Success.Log" TextColor="Silver" />
        <Label Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding SuccessRate, StringFormat='{}{0:P2}'}" HorizontalOptions="Center" TextColor="Silver" FontSize="36" />
 
        <Label Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Ratio}" HorizontalOptions="Center" TextColor="Silver" FontSize="24" />
 
        <chart:SfChart x:Name="Chart" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" BackgroundColor="Transparent">
 
			<chart:SfChart.PrimaryAxis>
				<chart:CategoryAxis LabelRotationAngle = "-45">
					<chart:CategoryAxis.Title>
						<chart:ChartAxisTitle Text ="Date"/>
					</chart:CategoryAxis.Title>
				</chart:CategoryAxis>
			</chart:SfChart.PrimaryAxis>
 
			<chart:SfChart.SecondaryAxis>
				<chart:NumericalAxis>
					<chart:NumericalAxis.Title>
						<chart:ChartAxisTitle Text ="Result"/>
					</chart:NumericalAxis.Title>
				</chart:NumericalAxis>
			</chart:SfChart.SecondaryAxis>
 
			<chart:SfChart.Series>
 
				<chart:ColumnSeries ItemsSource="{Binding DataPoints}" XBindingPath="Date" YBindingPath="Successes" Label="Successes" DataMarkerPosition = "Center" EnableDataPointSelection = "false" Color="Green">
					
					<chart:ColumnSeries.DataMarker>
						<chart:ChartDataMarker>
							<chart:ChartDataMarker.LabelStyle>
								<chart:DataMarkerLabelStyle LabelPosition = "Center"/>
							</chart:ChartDataMarker.LabelStyle>
						</chart:ChartDataMarker>
					</chart:ColumnSeries.DataMarker>
				</chart:ColumnSeries>
 
				<chart:ColumnSeries ItemsSource="{Binding DataPoints}" XBindingPath="Date" YBindingPath="Failures" Label="Failures" EnableDataPointSelection = "false" Color="Red">
					
					<chart:ColumnSeries.DataMarker>
						<chart:ChartDataMarker>
							<chart:ChartDataMarker.LabelStyle>
								<chart:DataMarkerLabelStyle LabelPosition = "Center"/>
							</chart:ChartDataMarker.LabelStyle>
						</chart:ChartDataMarker>
					</chart:ColumnSeries.DataMarker>
				</chart:ColumnSeries>
 
			</chart:SfChart.Series>
 
		</chart:SfChart>
 
		<Button Grid.Row="4" Grid.Column="0" Text="Failed" BackgroundColor="Red" Command="{Binding Failed}" />
		<Button Grid.Row="4" Grid.Column="1" Text="Succeeded" BackgroundColor="Green" Command="{Binding Success}" />
	</Grid>
 
</ContentPage>

Implementing the ViewModel

I partition my view-models into three layers:

  • ViewModel
  • ViewModel.commands
  • ViewModel.internal

ViewModel

public partial class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
 
    public ViewModel()
    {
        ActivateCommands();
        var dataPoints = new DataPointsRepository().GetDataPoints();
        DataPoints = new ObservableCollection<DataPoint>(dataPoints);
    }
 
    ObservableCollection<DataPoint> _datapoints = new ObservableCollection<DataPoint>();
    public ObservableCollection<DataPoint> DataPoints
    {
        get { return _datapoints; }
        set
        {
            if (_datapoints != value)
            {
                _datapoints = value;
                OnPropertyChanged();
            }
        }
    }
 
    decimal _successRate = 0.00m;
    public decimal SuccessRate
    {
        get { return _successRate; }
        set
        {
            if (_successRate != value)
            {
                _successRate = value;
                OnPropertyChanged();
            }
        }
    }
 
    string _ratio = null;
    public string Ratio
    {
        get { return _ratio; }
        set
        {
            if (_ratio != value)
            {
                _ratio = value;
                OnPropertyChanged();
            }
        }
    }
 
    public void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ViewModel.commands

ViewModel.commands
public partial class ViewModel
{
    void ActivateCommands()
    {
        Success = new DelegateCommand(obj => AddDataPoint(true));
        Failed = new DelegateCommand(obj => AddDataPoint(false));
        Undo = new DelegateCommand(UndoLast);
    }
 
    public DelegateCommand Success { get; private set; }
    public DelegateCommand Failed { get; private set; }
    public DelegateCommand Undo { get; private set; }
}

ViewModel.internal

public partial class ViewModel
{
    DataPointsRepository _repository = new DataPointsRepository();
 
    void AddDataPoint(bool isSuccessful)
    {
        var encounter = new Encounter() { IsSuccessful = isSuccessful };
        _repository.Add(encounter);
 
        var datapoints = _repository.GetDataPoints();
        DataPoints = new ObservableCollection<DataPoint>(datapoints);
 
        var totalCount = DataPoints.Sum(dp => dp.Successes + dp.Failures);
        var successCount = DataPoints.Sum(dp => dp.Successes);
        SuccessRate = (decimal)successCount / (decimal)totalCount;
        Ratio = $"{successCount} out of {totalCount}";
    }
 
    void UndoLast(object obj)
    {
        _repository.RemoveLast();
    }
}

Repository

I partition my repositories into two layers:

  • Repository
  • Repository.internal
public partial class DataPointsRepository
{
    public IEnumerable<Encounter> GetEncounters(DateTime date)
    {
        var compareDate = date.ToString(Constants.DATE_FORMAT);
 
        var result = _dateEncounters.FirstOrDefault(dp => dp.Key == compareDate);
 
        if (result.Value == null) return new HashSet<Encounter>();
 
        return result.Value;
    }
 
    public IEnumerable<Encounter> GetEncounters()
    {
        var list = new List<Encounter>();
        foreach (var encounter in _dateEncounters.Values)
        {
            list.AddRange(encounter);
        }
 
        return list;
    }
 
    public IEnumerable<DataPoint> GetDataPoints()
    {
        _datapointDictionary.Clear();
 
        var encounters = GetEncounters();
 
        foreach (var encounter in encounters)
        {
            DataPoint foundDatapoint = null;
            var exists = _datapointDictionary.TryGetValue(encounter.Date, out foundDatapoint);
 
            if (exists)
            {
                SetValue(encounter, foundDatapoint);
            }
            else
            {
                var datapoint = new DataPoint(encounter.Date);
 
                SetValue(encounter, datapoint);
                _datapointDictionary.Add(datapoint.Date, datapoint);
            }
        }
 
        return _datapointDictionary.Values;
    }
 
    public void Add(Encounter encounter)
    {
        var encounters = GetEncounters(DateTime.Now);
        var todaysEncounters = new HashSet<Encounter>(encounters);
        todaysEncounters.Add(encounter);
 
        _dateEncounters[DateTime.Now.ToString(Constants.DATE_FORMAT)] = todaysEncounters;
    }
}

Repository.internal

public partial class DataPointsRepository
{
    Dictionary<string, HashSet<Encounter>> _dateEncounters = new Dictionary<string, HashSet<Encounter>>();
    Dictionary<string, DataPoint> _datapointDictionary = new Dictionary<string, DataPoint>();
 
    void SetValue(Encounter encounter, DataPoint datapoint)
    {
        if (encounter.IsSuccessful) datapoint.Successes++;
        else datapoint.Failures++;
    }
}

Unit Tests

The following unit tests were written:

[TestClass]
public class _ViewModel
{
    [TestMethod]
    public void adding_success_and_failures_updates_datapoints()
    {
        // Setup
        var viewModel = new ViewModel();
 
        // Test
        viewModel.Failed.Execute(null);
        viewModel.Failed.Execute(null);
        viewModel.Success.Execute(null);
        viewModel.Success.Execute(null);
        viewModel.Success.Execute(null);
 
        // Verify
        var datapoint = viewModel.DataPoints.Single();
        var expected = datapoint.Successes == 3 &&
                       datapoint.Failures == 2 &&
                       viewModel.SuccessRate == .6m;
 
        Assert.IsTrue(expected);
    }
 
    [TestMethod]
    public void adding_success_updates_datapoints()
    {
        // Setup
        var viewModel = new ViewModel();
 
        // Test
        viewModel.Success.Execute(null);
 
        // Verify
        var datapoint = viewModel.DataPoints.Single();
        var expected = datapoint.Successes == 1 &&
                       datapoint.Failures == 0;
 
        Assert.IsTrue(expected);
    }
 
    [TestMethod]
    public void adding_failure_updates_datapoints()
    {
        // Setup
        var viewModel = new ViewModel();
 
        // Test
        viewModel.Failed.Execute(null);
 
        // Verify
        var datapoint = viewModel.DataPoints.Single();
        var expected = datapoint.Successes == 0 &&
                       datapoint.Failures == 1;
 
        Assert.IsTrue(expected);
    }
}

Conclusion

In conclusion, I have showed an example of most of the code involved for implementing a bar chart. Syncfusion provides a community edition to get started with graph charts integration.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net

Intro

I have experimented with some architectural ideas for building applications and would like to share my thoughts.

Quote Builder

I wrote Quote Builder using Clean Architecture. I built the app with the lessons I learned from the last implementation in 2012. This app (Windows Store) has about 10,000 downloads.

Clean Architecture

I am a disciple of Martin’s teachings. As a result, I decided to implement my interpretation of his Clean Architecture idea. I built Quote Builder three years ago and tried my hardest to conform to Microsoft’s user experience guidelines for their Metro design. That resulted in a third of the app’s ratings being one-star.

The client architecture of that version is below:

MetroArchitecture

The Clean Architecture approach that I built with Xamarin.Forms is the following:

XamarinArchitecture

A user-story module within the architecture is as follows:

XamarinSolutionExplorer

The Solution Explorer for the Windows Store app looks like the following:

MetroArchitecture_solutionExplorer

The Solution Explorer for Xamarin.Forms app looks like the following:

Xamarin_solutiion_explorer_architecture

The following table reflects code analysis results of the application including user story modules:

CodeMetrics

Retrospective on Clean Architecture

When I rewrote Quote Builder for Xamarin.Forms, I created a project per user story. I also created a unit test project per user story. This resulted in about 45 projects within my solution. Thus, this gave me long load times (approximately 15 seconds) when opening the solution in Visual Studio 2015. I also found myself waiting for half a minute each time I would build my solution. As a result, I consolidated my unit test projects to just one project which reduced load-time by a third.

Teams implementing Clean Architecture, need to respond to the organic growth of the software over time in which the application becomes proliferated with projects that take will eventually take a toll on a solution’s load-time and build processes. There are workarounds though. For example, multiple projects can be consolidated to one project based on the related concerns of user story modules. In addition, other solutions can be created per related set of modules. This will enable a solution to replace project dependencies with DLLs. Performing this substitution will reduce the time to load a solution, build it, and execute unit tests by orders of magnitude faster than relying on only projects.

I also like the side-effect of isolating user story modules. Hence, this architecture reduces the likelihood for the codebase to experience entropy. For example, the isolation of each user story module enables code analysis to be utilized more effectively. Hence we can now scrutinize each user story’s implementation which (because of this architecture) is now in complete isolation of other user stories. For example, we can now examine the maintainability index and code coverage from unit tests targeting a specific user story module. Thus, isolating user stories into independent modules for developers to pull from, will encourage developers to finally acknowledge ownership of their code’s quality because no other developer will modify their module without the owner’s review and approval. Another benefit is that user story modules that were poorly implemented can now be refactored or in some cases rewritten without having to rewrite a significant portion of the application. Also, developers that do hold themselves accountable for the quality of their code are  now enabled to lead by example. Hence, because their user story is isolated from the modules that other developers are tasked with, quality focused developers can now own the quality of their story and demonstrate how to write solid code with outstanding code coverage which other developers can reference and learn from.

I am not convinced that implementing Clean Architecture is worth the overhead for a single developer project. I do believe that this practice will encourage developers to be more surgical when it comes to maintaining an application’s architecture due to isolated user story responsibilities.

In addition, I do believe that clean architecture makes software more maintainable over the long run. Developers can now zero-in on a user story module that’s most likely to host a reported bug. It also compliments Visual Studio’s CodeMap so that maintainers can identify dependencies of specific user-stories as the user-story module diagram conveyed.

Conclusion

In conclusion, I ported a Windows Store app to Xamarin.Forms using Clean Architecture. I provided disclaimers about using Clean Architecture in regards to load-times with Visual Studio solutions and what can be done to resolve those concerns. I also identified the benefits of leveraging this pattern in regards to refactoring or rewriting a user story module as well as the increase in code quality.

NOTE:

Scott Nimrod is fascinated with Software Craftsmanship.

He loves responding to feedback and encourages people to share his articles.

He can be reached at scott.nimrod @ bizmonger.net