## Time Tortoise: Reading and Writing Text Files in UWP Apps

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

As described last week, I’m starting to build infrastructure for a text file UI: a way to use text files for user input and program output, rather than relying completely on the graphical XAML UI. This week, I’m looking into the specifics of text file I/O for UWP apps.

« Continue »

## Time Tortoise: Text File User Interface

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

A Time Tortoise feature consists of a user interface, and one or more components to support that UI. The MVVM pattern provides a way to separate the UI from the supporting components, to help make the code more understandable, and facilitate unit testing.

In my experience, building a feature with a corresponding graphical UI is almost like building two separate features. Creating the model and view model requires writing functions that are called by other functions. Unit testing these components is straightforward, since unit tests are just another kind of function. But building the view (the UI) is different. Although there may be functions in the view layer, the main work is laying out controls in a way that is intuitive for the user. That work requires different skills, and the result is almost impossible to unit test.

This week, I’m exploring a UI paradigm that supplements graphical buttons and lists with a textual approach.

## Graphical UI

For some features, the best UI is a graphical one. For Time Tortoise, that applies to all of the features that are currently implemented. For example, clicking on a list item is an intuitive way to select an activity, and a digital clock is a clear way to represent work times.

In general, a graphical UI is preferable when a user selection should lead to an immediate change in the UI. For example, clicking an activity loads a list of time segments, or clicking the Start/Stop button starts or stops the activity timer. Implementing features like this in a GUI makes an app easier to use and more interactive.

For the app developer, the trade-off with GUI implementations is the extra development time required to get the visual elements right. So it’s worth considering how a feature would work using other UI approaches.

## Command-Line UI

The most basic non-graphical UI is the command line. Familiar to UNIX aficionados and power users in general, it’s a way to expose features of an application without a lot of UI work. For a sophisticated user, a command-line UI can make it easy to execute common app functions. Rather than clicking around, they can quickly type and run a command. For example, there could be a command like TimeTortoise start <ActivityName> to start timing an activity. These commands can even be automated using scripts.

A well-known disadvantage of the command-line UI is that it requires users to remember command names. A console window also isn’t optimal for presenting interactive or frequently-changing data. In the TimeTortoise start example, it might be useful to start the timer from the command line, but a running timer is better shown in a window, along with the corresponding time segments and their time totals.

## Text File UI

Consider a UI that relies on the user typing commands into a text file rather than a command window. This may sound like a strange user interface, but it’s the primary way that programmers interact with a compiler. Compilers have command-line interfaces and often graphical interfaces as well, but their main purpose is to process text files.

If an app is reading user input from a text file, it makes sense to also write output to a text file. This text output is analogous to the output that appears in the console window in the command-line scenario. We could even combine the two, writing to a text file that the user then edits for subsequent reading.

One way to think about the text file UI is as a way to reuse the UI from the user’s favorite text editor. So while the app developer only has to read and write text files, the user can take advantage of copy/paste, find, scroll, auto-reload, and other features of their chosen editor.

## Format

For the input text file, it’s important that the file format be easy to read and edit, but also parseable by the app. A format like XML can be parsed using standard tools, but it’s not very friendly for reading and editing. Formats like JSON and YAML have been developed to address the readability issue.

## Examples

Here are a few examples of how a text file UI could be useful for Time Tortoise:

Settings

Many apps have a settings section for adjusting how the app works. It tends to have a lot of UI elements, so the developer has to create and arrange those elements in the designer. For an MVVM app, this also means creating a lot of view model properties to move the data around. To simplify the development of a settings feature, the settings could be read from a text file.

Time segments

In a time tracking app, it’s sometimes necessary for the user to manipulate the day’s time segments after they have been recorded. An input text file could facilitate bulk editing: the user could make changes in the text file, and the app could then read the result and update the database. In this scenario, the output text file could contain a comma-separated version of the data for easy copying and pasting into a spreadsheet.

Daily summary

An output text file could be used to summarize the day’s activity, with a list of time segments and time totals. Free-form notes extracted from the input file could allow the user to supplement the data with comments on the day’s work.

(Image credit: Dan Ho)

## Time Tortoise: Class Library Project Types

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

This week saw the release of .NET Standard 2.0. According to the announcement, I’ll have to wait until “later this year” to use it in the Time Tortoise UWP project. But I thought it would be a good time to discuss some related topics that have come up in recent weeks as I’ve been adding to the Time Tortoise solution.

Visual Studio organizes code in projects, which can be collected together in a solution. When you create a new project, Visual Studio first asks that you specify a project type. It uses this type to select a template which defines characteristics of the project and a starting set of code files.

The Time Tortoise solution now contains a total of 12 projects of these types:

• A .NET Core Console App for manually testing the .NET Core class libraries.
• A Windows Classic Desktop console app for manually testing the Windows Classic Desktop class library.
• Seven .NET Core/.NET Standard class libraries.
• A Windows Classic Desktop class library (TimeTortoise.Server)
• A Windows Presentation Foundation (WPF) app, the host app for Time Tortoise Companion.
• A Universal Windows Platform (UWP) app, the host app for Time Tortoise itself.

This week, I’ll be focusing on the .NET Core/.NET Standard class libraries.

## .NET Core Class Libraries

A class library project compiles to an assembly (.NET DLL) that other projects can reference. For example, the Time Tortoise UWP project references the class library TimeTortoise.ViewModel, which contains classes that support the user interface.

Class libraries are convenient for unit testing because they’re designed to be called by other code. There’s no user interface to make testing difficult, as with console or UWP app projects. So my policy for Time Tortoise is to put as much code as possible in class libraries.

UWP apps can’t reference Windows Classic Desktop class libraries. Those can only be used by WPF and other pre-UWP project types. For UWP apps, we need to use .NET Core class libraries.

## .NET Standard vs. .NET Core

The .NET Standard is a “formal specification,” while .NET Core is one particular implementation of the standard. Or in OOP terms, .NET Standard is like an interface and .NET Core is like a concrete implementation of that interface.

One thing to keep in mind about this definition is that Visual Studio provides class library project types for both .NET Core and .Net Standard. So for a class library, you can choose to target either one. By targeting .NET Core, you get access to a bit more functionality, but some of that functionality may not be compatible with other .NET Standard implementations. Choosing the .NET Standard class library project type ensures that you’ll only use functionality that every .NET Standard implementation supports.

## Class Library Project Types in Visual Studio

One way to learn about project types is to examine what they look like in Visual Studio Solution Explorer. As an experiment, I created one of each of these class library project types in Visual Studio 2017:

Windows Classic Desktop Class Library

This is the traditional class library that has been available since the early days of .NET. It has the following sections:

• A Properties section containing AssemblyInfo.cs, a class with information about the assembly.
• A References section with default references, including System, System.Core, System.Data, and others.
• Class1.cs, an empty class with default using statements.

The components of the project (files, references, and other information) for this project type are stored in a .csproj file.

.NET Core

In this project type, the References section has been renamed to Dependencies. The section has a reference to Microsoft.NETCore.App, which contains a long list of core assemblies, including System.Collections.Immutable, System.Linq.Expressions, and many others.

The Properties section has been removed, and the default class file refers only to System.

A .csproj file is used, but it starts out very small compared to the classic csproj. As properties are modified from their default values, sections are added to the csproj. Another csproj change for .NET Core: project files don’t need to be explicitly referenced. Instead, they show up in Solution Explorer as soon as they are created in the project directory.

.NET Standard

The difference between the .NET Standard and .NET Core project types is that the .NET Standard project type references a dependency called NETStandard.Library, with a different set of standard assemblies.

Portable Class Library

This project type has been deprecated as of .NET Standard 2.0. It contains Properties and References sections like the Classic type, and a verbose .csproj file. But it also uses a file called project.json that is referenced in the csproj, and defines frameworks, dependencies, and supported environments.

## One More Type, as Used By the Time Tortoise Solution

I started Time Tortoise development at the beginning of 2017, before Visual Studio 2017 was out of beta. I also had some specific requirements for class libraries that could be both tested by xUnit.NET and referenced by a UWP project. As described in my first unit testing post, the following approach was the one that worked best for creating class library projects:

• Create a Portable Class Library project.
• In Project Properties, click Target .NET Platform Standard.

The result is a project that looks like a Portable Class Library project. It has Properties and References section, a project.json file, and even a (Portable) designation appended to the project name in Solution Explorer. But it targets NETStandard.Library.

For now, this configuration is working well, even now that I have added classic project types to the solution for Time Tortoise Companion. But I should ideally just target .NET Standard directly, without starting with a Portable Class Library. A good time to try out this change will be later in 2017 when UWP supports .NET Standard 2.0. At that time, I’ll try recreating the class library projects as .NET Standard 2.0 projects, and see if everything still works.

## Time Tortoise: Idle Time Unit Testing, Part 2

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

I’m in the process of resolving a unit test backlog for the Time Tortoise idle time feature. Last month, I explained why it’s acceptable in some situations to delay writing unit tests. I also covered a couple of unit testing best practices: interface-based design and minimizing the size of code-behind classes.

Over the past two weeks, I covered some challenges related to .NET assembly dependencies.

This week: more details on the idle time unit tests.

« Continue »

## Time Tortoise: Resolving Dependencies Part 2

This is one in a series of articles about Time Tortoise, a Universal Windows Platform app for planning and tracking your work schedule. For more on the development of this app and the ideas behind it, see my Time Tortoise category page.

Last week, I wrote about techniques to find a list of the .NET assemblies that xUnit.net needs to run unit tests. To review:

• When Visual Studio compiles a unit test project, it doesn’t copy all of the required dependencies into the output directory.
• Therefore, we need a way to manually find these dependencies.
• To find the dependencies, we can attempt to run unit tests and look for detailed error messages. One messages is shown when a FileLoadException occurs. Another one is found in Assembly Binding Log Viewer output: “All probing URLs attempted and failed.” Using these messages, we can manually copy dependencies to the unit test project output directory.
• If these debugging techniques uncover the need for two or more assemblies with different versions, binding redirection can be used to define a single version to use.

Missing dependencies prevent Visual Studio from discovering unit tests (i.e., finding them so they can be listed in Test Explorer). Using these debugging techniques, we should be able to successfully discover all of the unit tests in a project. The next step is to try to run the discovered tests.

« Continue »