SOLID Programming with Portable Class Libraries

47
Vagif Abilov SOLID programming with portable class libraries

Transcript of SOLID Programming with Portable Class Libraries

Page 1: SOLID Programming with Portable Class Libraries

Vagif Abilov

SOLID programming with

portable class libraries

Page 2: SOLID Programming with Portable Class Libraries

About myself

• Mail: [email protected]

• Twitter: @ooobject

• GitHub: object

• BitBucket: object

• Blog: http://bloggingabout.net/blogs/vagif/default.aspx

• Some articles: http://www.codeproject.com

• Some open source projects:

– Simple.Data OData adapter

– Simple.OData.Client

– MongOData

– PCL Conformance Analyzer

Page 3: SOLID Programming with Portable Class Libraries

Poll: do you care about PCL?

• Are you familiar with the concept of PCL?

• Have you used portable class libraries?

• Have you built your own portable class libraries?

• Do you maintain source code for applications that need

to be deployed on multiple platforms?

Page 4: SOLID Programming with Portable Class Libraries

By the way, what is «portability»?

According to Wikipedia:

Portability in high-level computer programming is the

usability of the same software in different environments.

Strategies for portability

• Transferring installed program files to another computer of basically

the same architecture.

• Reinstalling a program from distribution files on another computer of

basically the same architecture.

• Building executable programs for different platforms from source

code; this is what is usually understood by "porting".

Page 5: SOLID Programming with Portable Class Libraries

Portabilitity definition (cont’d)

Achieving portability between different processors,

according to Wikipedia:

• Non-web programs, installed upon a computer in the

normal manner, can have more control, and yet achieve

system portability by linking to the Java package.

• Software can be recompiled and linked from source

code for different operating systems and processors if

written in a programming language supporting

compilation for the platforms.

Page 6: SOLID Programming with Portable Class Libraries

Innovative portability strategies

• Xamarin products: compiling to native apps

– Binding Objective-C libraries (iOS)

– Binding Java libraries (Android)

• Portable class libraries: managed assemblies that work

on more than one .NET Framework platform

– .NET 4.0, 4.0.3, 4.5

– Silverlight 4, 5

– Windows Phone 7, 7.5, 8

– .NET for Windows Store applications

– Xbox 360

Page 7: SOLID Programming with Portable Class Libraries

Recompilation vs. binary reuse

Does it really matter if we package code in

reusable assemblies? Can we compile our

code for a new target platform when we

actually need it?

Page 8: SOLID Programming with Portable Class Libraries

PCL advantages

• If the code is not bound to a specific platform, then

packaging it in a portable class library will guard it from

unintended platform dependencies by enforcing

portability constraints at early development stage

• Packaging code as PCL may require introduction of

higher level abstractions, extraction of interfaces,

inversion of dependencies and provide guidance to

follow SOLID principles

Page 9: SOLID Programming with Portable Class Libraries

Platform support in PCL

Page 10: SOLID Programming with Portable Class Libraries

Authoring portable class libraries

Page 11: SOLID Programming with Portable Class Libraries

Case study

From

Simple.Data OData adapter

to

Simple.OData.Client PCL

Page 12: SOLID Programming with Portable Class Libraries

What is Simple.Data

• A lightweight, dynamic data access component for

.NET

• Written and maintained by Mark Rendle

• Adapters for SQL Server, Oracle, Sqlite, MongoDB,

OData, Oracle, PostgreSql, Informix

• An alternative to ORM libraries, such as Entity

Framework and NHibernate

Page 13: SOLID Programming with Portable Class Libraries

Simple.Data code example

var db = Database.Open();

var titles = db.Albums

.All()

.Select(db.Albums.Title)

.Where(db.Albums.GenreId == 1 &&

db.Albums.AlbumId > 400);

Page 14: SOLID Programming with Portable Class Libraries

Simple.Data OData adapter

• An alternative to WCF DataServices client

• Better fits RESTful nature of OData protocol than SOAP

alike client code generation triggered with «Add Service

Reference»

Page 15: SOLID Programming with Portable Class Libraries

Simple.Data.OData code example

var db = Database.Opener.Open(

"http://packages.nuget.org/v1/FeedService.svc/");

var package1 = db.Packages

.FindByTitle("Simple.Data.OData");

var package2 = db.Packages

.Find(db.Packages.Title == "Simple.OData.Client");

Generate HTTP GET request URLs:

Packages?$filter=Title+eq+%27Simple.Data.OData%27

Packages?$filter=Title+eq+%27Simple.OData.Client%27

Page 16: SOLID Programming with Portable Class Libraries

Adapter

• Structural design pattern

• Converts the interface of a class into another interface

clients expect

Common API

Adapter

External service

Page 17: SOLID Programming with Portable Class Libraries

Simple.Data OData version <= 0.5

Simple.Data API

Simple.Data OData Adapter

OData protocol

Page 18: SOLID Programming with Portable Class Libraries

ODataPad

Page 19: SOLID Programming with Portable Class Libraries

Making the adapter portable

• An adapter can target new platforms as long as it

provides a bridge between interfaces (and interfaces

don’t refer to types bound to specific platforms)

• OData protocol is platform agnostic

• Most of OData adapter code deals with either parsing

XML documents returned by an OData service or

formatting CLR objects as XML documents to send to

OData service

• Simple.Data API uses types defined in Simple.Data

library

• Simple.Data supports Mono (hope of portability with

other platforms)

Page 20: SOLID Programming with Portable Class Libraries

Targeting Windows Store apps

Page 21: SOLID Programming with Portable Class Libraries

System.Data namespace

• Microsoft.SqlServer.Server

• System.Configuration

• System.Data

• System.Data.Common

• System.Data.Odbc

• System.Data.OleDb

• System.Data.Sql

• System.Data.SqlClient

• System.Data.SqlTypes

• System.Xml

Page 22: SOLID Programming with Portable Class Libraries

PCL Conformance Analyzer

Demo

Page 23: SOLID Programming with Portable Class Libraries

Simple.Data.OData version >= 0.6

Simple.Data API

Simple.Data OData Adapter

Simple.OData.Client PCL

OData protocol

Page 24: SOLID Programming with Portable Class Libraries

Simple.OData.Client

• Version 0.13

– .NET 4.0, .NET 4.0.3, 4.5

– Windows Store

– Silverlight 5

– Windows Phone 8

• Version 0.17

– Xamarin.Android

– Xamarin.iOS

Page 25: SOLID Programming with Portable Class Libraries

But what about SOLID principles?

Example

Adding support for authentication

Page 26: SOLID Programming with Portable Class Libraries

User request: support authentication

• First implementation: accept user credentials (user +

password), create authentication object using one of

supported schemes (Basic, Windows etc.)

• Worked like a charm, easy to use in client code

var odataFeed = new ODataFeed(

"http://www.myservice.com/api",

"Vagif",

"Password123");

• At that time Simple.Data OData adapter included non-

portable version of Simple.OData.Client

Page 27: SOLID Programming with Portable Class Libraries

ODataFeed

public class ODataFeed

{

public string Url { get; set; }

public string User { get; set; }

public string Password { get; set; }

public string Domain { get; set; }

public bool IntegratedSecurity { get; set; }

}

Page 28: SOLID Programming with Portable Class Libraries

Creating Web request

var request = (HttpWebRequest)WebRequest.Create(uri);

if (this.Credentials.IntegratedSecurity)

{

request.Credentials = CredentialCache.DefaultNetworkCredentials;

}

else if (!string.IsNullOrEmpty(this.Credentials.User))

{

request.Credentials = new NetworkCredential(

this.Credentials.User,

this.Credentials.Password,

this.Credentials.Domain);

}

Page 29: SOLID Programming with Portable Class Libraries

Merging with Portable branch

Project doesn’t compile!

• System.Net.CredentialCache: .NET 4.x only

• System.Net.NetworkCredential: most of platforms

Page 30: SOLID Programming with Portable Class Libraries

What went wrong?

• Simple.Data OData adapter took responsibility to create

user credentials based on sensitive user information

• Leaving aside security aspects, the adapter violated

single responsibility principle

• The adapter restricted supported authentication metods

to those provided by credential creation code

• The adapter is not open to extending it with new

authentication methods, so it violated open/closed

principle too

• Use of interface segregation principle would avoid this

mistake

• PCL compliance forced use of interfaces

Page 31: SOLID Programming with Portable Class Libraries

Revised implementation

In platform-spefic client code

var odataFeed = new ODataFeed(

"http://www.myservice.com/api",

credentials);

In Simple.OData.Client PCL

var request = (HttpWebRequest)WebRequest.Create(uri);

request.Credentials = this.Credentials;

Page 32: SOLID Programming with Portable Class Libraries

Revised implementation

• Credentials is an instance of a class that implements

System.Net.ICredentials interface

• Neither Simple.Data OData adapter (.NET 4.x) nor

Simple.OData.Client refer to a specific authentication

scheme

• All present and future authentication schemes are

supported as long as they conform ICredentials

Page 33: SOLID Programming with Portable Class Libraries

Observations

• Some SOLID principles require coding discipline and

leave a room for interpretation, IMHO especially SRP

and OCP (John Skeet on OCP: «While I've obviously considered the

possibility that I'm the only one who finds it confusing, I've heard enough variation in

the explanations of it to suggest that I'm really not the only one»)

• PCL conformance requirement doesn’t release you

from the responsibility to make the design decision, but

it can guard you from making obvious mistakes and

sometimes even guide you in a right direction

• PCLs make you more carefully plan service

instantiation and use of non-functional utilities (logging,

instrumentation etc.)

Page 34: SOLID Programming with Portable Class Libraries

PCLs and concrete classes

• Portable class libraries do not push the work of

implementing platform-specific services to client

applications

• PCLs can be packaged as a single portable deployment

unit

– Autofac

– Json.NET

– Simple.OData.Client

• PCLs can also be compound, consisting of core

portable and platform-specific parts

– MetroLog

– Splat

Page 35: SOLID Programming with Portable Class Libraries

MetroLog architecture

Page 36: SOLID Programming with Portable Class Libraries

MetroLog NuGet specification

<files>

<file src="MetroLog.dll" target="lib\portable-

net45+wp8+win8\MetroLog.dll" />

<file src="MetroLog.dll" target="lib\net45\MetroLog.dll" />

<file src="MetroLog.NetFx.dll" target="lib\net45\MetroLog.NetFx.dll" />

<file src="MetroLog.dll" target="lib\netcore45\MetroLog.dll" />

<file src="MetroLog.NetCore.dll"

target="lib\netcore45\MetroLog.NetCore.dll" />

</files>

Page 37: SOLID Programming with Portable Class Libraries

PCLs consuming PCLs

• A PCL client can also be a portable library

• Client target platforms must be a subset of the

referenced PCL’s target platforms

• Functionality that requires platform-specific services is

usually referred using interfaces and abstract classes

• There is a trick to use concrete platform-specific

classes in client PCLs by placing in the referenced PCL

a dummy class with the same API surface and

assembly identity as the platform-specific class

Page 38: SOLID Programming with Portable Class Libraries

PCL profiles and portable subsets

• Profile is a set of supported platforms

• Portable subset is a family of profiles that expose

certain version of .NET FX API surface area

– Profile 78: Portable Subset:

• .NET 4.5

• Windows Phone 8

• Windows Store

– Profile 95: Portable Subset (Legacy):

• .NET 4.0.3 and higher

• Silverlight 4 and higher

• Windows Phone 7 and higher

• Windows Store

Page 39: SOLID Programming with Portable Class Libraries

PCLs for Android and iOS

Demo: Xamarin .NET Mobility Scanner

Example: Reflection API portability

Page 40: SOLID Programming with Portable Class Libraries

Polyglot programming with PCLs

• Use right language to solve specific problems

• C# provides the best ‘one size fits all’ choice

• F# is very efficient for immutable data transformations,

financial computations, machine learning

• F# code can be packaged in a PCL and shared among

different platforms (inluding Android and iOS!)

– No official support to target Windows Phone 8 using F# PCL, but there

is a workaround

– Both PCL and F# support in Xamarin are work in progress (with

changes being made literally while I am speaking now)

• Core logic can be written in C# and F# and packaged

as PCL, and UI is added using platform-specific tools

Page 41: SOLID Programming with Portable Class Libraries

PCLs for the future

• Profiles for v.4.0 API surface are being deprecated

• Visual Studio 2013 can open PCLs that target legacy

platforms, but it will upgrade Silverlight to target version

5 and Windows Phone to target version 8

• Xamarin PCLs targets both v.4.0 and v.4.5 API surfaces

• If a library target wide range of platforms (both 4.0 and

4.5), its NuGet package should include separate binaries

for each surface

• Consider only targeting v.4.5 API surface for new

projects unless you need to support legacy platforms

Page 42: SOLID Programming with Portable Class Libraries

Using PCLs in UI

• Use of portable class libraries can result in significant

code reuse in cross-platform application development

• Most popular approach to cross-platform UI with PCLs

is to use MVVM pattern and package core services,

models and view models in a portable library

• Most popular MVVM frameworks that have PCLs are

MvvmLights and MvvmCross

• MvvmCross supports targeting Xamarin.iOS and

Xamarin.Android (and provides phenomenal support at

StackOverflow by @slodge)

Page 43: SOLID Programming with Portable Class Libraries

Example: Lions Roar

• Developed by Sequence Agency

• UI is built using MvvmCross

• View models PCL (2463 LOC)

• Entities PCL (691 LOC)

• Supported plalforms

– Windows Store (1166 LOC)

– Windows Phone 8 (668)

– Android Phone/Tablet (1172)

– iPhone/iPad (2000 LOC)

Page 44: SOLID Programming with Portable Class Libraries

Using PCL in ODataPad UI

• ODataPad views show images

• Original view model design included core portable base

view model (without image data) and platform-specific

view models (with image data)

• Small picture size makes possible storing images in

base64 format and reuse a single view model in all

platforms

• Rendering images requires platform-specific value

converters

• A PCL with a design-time view model serves design

data to all Visual Studio designers (Blend)

Page 45: SOLID Programming with Portable Class Libraries

Conclusion

• Portable class libraries are not only for binary reuse

• Packaging code as PCLs helps making code cleaner:

– Extract interfaces

– Unify platform-specific services

– Inject service dependencies

– Use portable data structures

• Consider PCLs when choosing third party libraries

– Ready for other platforms

– Indication of a proper design

– May only have dependencies to other portable libraries

• Consider make your next library portable even if you

only target a single platform!

Page 46: SOLID Programming with Portable Class Libraries

Resources

• Daniel Plaisted «How to Make Portable Class Libraries

Work for You»

• Scott Hanselman «Cross-Platform Portable Class

Libraries with .NET are Happening»

Open source projects at GitHub:

• AutoFac

• MetroLog

• Splat

• MvvmCross

• Simple.OData.Client

Page 47: SOLID Programming with Portable Class Libraries

Thank you!

• Mail: [email protected]

• Twitter: @ooobject

• GitHub: object

• BitBucket: object

• Blog: http://bloggingabout.net/blogs/vagif/default.aspx

The source code for this PCL Conformance Analyzer can

be found at https://github.com/object/PclAnalyzer