SOLID programming with portable class libraries Vagif Abilov
About myself • Mail: vagif.abilov@gmail.com • 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
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?
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".
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.
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
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?
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
Platform support in PCL
Authoring portable class libraries
Case study From Simple.Data OData adapter to Simple.OData.Client PCL
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
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);
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»
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
Adapter • Structural design pattern • Converts the interface of a class into another interface clients expect Common API Adapter External service
Simple.Data OData version <= 0.5 Simple.Data API Simple.Data OData Adapter OData protocol
ODataPad
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)
Targeting Windows Store apps
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
PCL Conformance Analyzer Demo
Simple.Data.OData version >= 0.6 Simple.Data API Simple.Data OData Adapter Simple.OData.Client PCL OData protocol
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
But what about SOLID principles? Example Adding support for authentication
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
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; } }
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); }
Merging with Portable branch Project doesn’t compile! • System.Net.CredentialCache: .NET 4.x only • System.Net.NetworkCredential: most of platforms
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
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;
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
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.)
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
MetroLog architecture
MetroLog NuGet specification <files> <file src="MetroLog.dll" target="libportable-net45+ wp8+win8MetroLog.dll" /> <file src="MetroLog.dll" target="libnet45MetroLog.dll" /> <file src="MetroLog.NetFx.dll" target="libnet45MetroLog.NetFx.dll" /> <file src="MetroLog.dll" target="libnetcore45MetroLog.dll" /> <file src="MetroLog.NetCore.dll" target="libnetcore45MetroLog.NetCore.dll" /> </files>
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
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
PCLs for Android and iOS Demo: Xamarin .NET Mobility Scanner Example: Reflection API portability
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
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
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)
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)
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)
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!
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
Thank you! • Mail: vagif.abilov@gmail.com • 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

SOLID Programming with Portable Class Libraries

  • 1.
    SOLID programming with portable class libraries Vagif Abilov
  • 2.
    About myself •Mail: vagif.abilov@gmail.com • 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
  • 3.
    Poll: do youcare 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?
  • 4.
    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".
  • 5.
    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.
  • 6.
    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
  • 7.
    Recompilation vs. binaryreuse 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?
  • 8.
    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
  • 9.
  • 10.
  • 11.
    Case study From Simple.Data OData adapter to Simple.OData.Client PCL
  • 12.
    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
  • 13.
    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);
  • 14.
    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»
  • 15.
    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
  • 16.
    Adapter • Structuraldesign pattern • Converts the interface of a class into another interface clients expect Common API Adapter External service
  • 17.
    Simple.Data OData version<= 0.5 Simple.Data API Simple.Data OData Adapter OData protocol
  • 18.
  • 19.
    Making the adapterportable • 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)
  • 20.
  • 21.
    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
  • 22.
  • 23.
    Simple.Data.OData version >=0.6 Simple.Data API Simple.Data OData Adapter Simple.OData.Client PCL OData protocol
  • 24.
    Simple.OData.Client • Version0.13 – .NET 4.0, .NET 4.0.3, 4.5 – Windows Store – Silverlight 5 – Windows Phone 8 • Version 0.17 – Xamarin.Android – Xamarin.iOS
  • 25.
    But what aboutSOLID principles? Example Adding support for authentication
  • 26.
    User request: supportauthentication • 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
  • 27.
    ODataFeed public classODataFeed { 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; } }
  • 28.
    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); }
  • 29.
    Merging with Portablebranch Project doesn’t compile! • System.Net.CredentialCache: .NET 4.x only • System.Net.NetworkCredential: most of platforms
  • 30.
    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
  • 31.
    Revised implementation Inplatform-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;
  • 32.
    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
  • 33.
    Observations • SomeSOLID 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.)
  • 34.
    PCLs and concreteclasses • 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
  • 35.
  • 36.
    MetroLog NuGet specification <files> <file src="MetroLog.dll" target="libportable-net45+ wp8+win8MetroLog.dll" /> <file src="MetroLog.dll" target="libnet45MetroLog.dll" /> <file src="MetroLog.NetFx.dll" target="libnet45MetroLog.NetFx.dll" /> <file src="MetroLog.dll" target="libnetcore45MetroLog.dll" /> <file src="MetroLog.NetCore.dll" target="libnetcore45MetroLog.NetCore.dll" /> </files>
  • 37.
    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
  • 38.
    PCL profiles andportable 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
  • 39.
    PCLs for Androidand iOS Demo: Xamarin .NET Mobility Scanner Example: Reflection API portability
  • 40.
    Polyglot programming withPCLs • 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
  • 41.
    PCLs for thefuture • 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
  • 42.
    Using PCLs inUI • 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)
  • 43.
    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)
  • 44.
    Using PCL inODataPad 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)
  • 45.
    Conclusion • Portableclass 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!
  • 46.
    Resources • DanielPlaisted «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
  • 47.
    Thank you! •Mail: vagif.abilov@gmail.com • 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