{"id":187,"date":"2016-09-08T15:13:24","date_gmt":"2016-09-08T15:13:24","guid":{"rendered":"http:\/\/thibaultklein.com\/ios\/?p=187"},"modified":"2016-09-08T15:13:24","modified_gmt":"2016-09-08T15:13:24","slug":"a-functional-approach-to-validation-using-protocol-oriented-programming","status":"publish","type":"post","link":"https:\/\/thibaultklein.com\/ios\/a-functional-approach-to-validation-using-protocol-oriented-programming\/","title":{"rendered":"A Functional Approach to Validation using Protocol Oriented Programming"},"content":{"rendered":"<p>I wrote an <a href=\"http:\/\/thibaultklein.com\/ios\/a-functional-approach-to-uitextfield-validation\/\">article<\/a> about how I took a functional approach to implement some <code>UITextField<\/code> validation. In this article I detailed how the functional approach helped me defining small functions easy to use and test. After thinking about the implementation I realized that the code worked great but was only available for <code>UITextField<\/code>. It wasn\u2019t reusable for anything else that could need the same kind of validation. I basically broke an important <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2015\/408\/\">protocol-oriented<\/a> maxim: if you want to create a class, create a protocol first. <\/p>\n<p>This time, instead of creating a class extension, I will start with protocols:<\/p>\n<pre><code>protocol Validatable {\r\n    associatedtype T\r\n\r\n    func validate(_ functions: [T]) -&gt; Bool\r\n}\r\n\r\nprotocol Evaluatable {\r\n    associatedtype T\r\n\r\n    func evaluate(with condition: T) -&gt; Bool\r\n}\r\n<\/code><\/pre>\n<p>The evaluate and validate features are now available for anyone conforming to them. Note that I\u2019m using associated types to make the validation and evaluation types generic to increase their genericity.<\/p>\n<p>Let\u2019s now revisit the <code>UITextField<\/code> example using these protocols:<\/p>\n<pre><code>extension UITextField: Validatable {\r\n    func validate(_ functions: [(String) -&gt; Bool]) -&gt; Bool {\r\n        return functions.map { f in f(self.text ?? &quot;&quot;) }.reduce(true) { $0 &amp;&amp; $1 }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>We extend the <code>UITextField<\/code> class to conform to <code>Validatable<\/code> and the validation logic stays the same. The associated type is defined here as a <code>String -&gt; Bool<\/code> function.<\/p>\n<pre><code>extension String: Evaluatable {\r\n    func evaluate(with condition: String) -&gt; Bool {\r\n        guard let range = range(of: condition, options: .regularExpression, range: nil, locale: nil) else {\r\n            return false\r\n        }\r\n\r\n        return range.lowerBound == startIndex &amp;&amp; range.upperBound == endIndex\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>We extend the <code>String<\/code> class to conform to <code>Evaluatable<\/code> and implement the same logic as before. The associated type is defined here as a <code>String<\/code> type.<\/p>\n<p>Now we can use the evaluation functions exactly the same way as before:<\/p>\n<pre><code>func isCVCValid(text: String) -&gt; Bool {\r\n    let regexp = &quot;^[0-9]{3,4}$&quot;\r\n    return text.evaluate(with: regexp)\r\n}\r\n\r\nlet cvcTextField = UITextField()\r\ncvcTextField.text = &quot;123&quot;\r\ncvcTextField.validate([isCVCValid])\r\n<\/code><\/pre>\n<h3>Another Use for Our Protocols<\/h3>\n<p>Let\u2019s see how using protocols can be beneficial for a complete different part of your code. Let\u2019s take an example with a <code>User<\/code> model that you want to validate:<\/p>\n<pre><code>struct User {\r\n    let firstName: String\r\n    let lastName: String\r\n    let age: Int\r\n}\r\n<\/code><\/pre>\n<p>We can make <code>User<\/code> conform to our <code>Validatable<\/code> protocol:<\/p>\n<pre><code>extension User: Validatable {\r\n    func validate(_ functions: [(User) -&gt; Bool]) -&gt; Bool {\r\n        return functions.map { f in f(self) }.reduce(true) { $0 &amp;&amp; $1 }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>The associated type is defined as a <code>User -&gt; Bool<\/code> function because we want to take a user as a parameter and return a boolean value to validate it.<\/p>\n<p>Let\u2019s also define the evaluation functions we will use:<\/p>\n<pre><code>func isUserNameValid(user: User) -&gt; Bool {\r\n    let regexp = &quot;[A-Za-z] &quot;\r\n    return user.firstName.evaluate(with: regexp) &amp;&amp; user.lastName.evaluate(with: regexp)\r\n}\r\n\r\nfunc isUserAdult(user: User) -&gt; Bool {\r\n    return user.age &gt;= 18\r\n}\r\n<\/code><\/pre>\n<p>Finally we can create a user and test the validation feature:<\/p>\n<pre><code>let user = User(firstName: &quot;Thibault&quot;, lastName: &quot;Klein&quot;, age: 25)\r\nXCTAssertTrue(user.validate([isUserNameValid, isUserAdult]))\r\n<\/code><\/pre>\n<p>The validation and evaluation features are now available for another type that I defined. On top of that it still keeps the benefits of functional programming I described in my previous article. This example might not be the most useful one possible, but it gives you a sense that anything can be validated now that I moved all the logic into protocols.<\/p>\n<p>I definitely recommend thinking towards protocol first the next time you want to introduce a new feature in your code, as it can make it more flexible, descriptive, and reusable in the future.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote an article about how I took a functional approach to implement some UITextField validation. In this article I detailed how the functional approach helped me defining small functions easy to use and test. After thinking about the implementation I realized that the code worked great but was only available for UITextField. It wasn\u2019t&hellip; <a class=\"more-link\" href=\"https:\/\/thibaultklein.com\/ios\/a-functional-approach-to-validation-using-protocol-oriented-programming\/\">Continue reading <span class=\"screen-reader-text\">A Functional Approach to Validation using Protocol Oriented Programming<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-187","post","type-post","status-publish","format-standard","hentry","category-ios","entry"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p6mZvu-31","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/posts\/187","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/comments?post=187"}],"version-history":[{"count":1,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/posts\/187\/revisions"}],"predecessor-version":[{"id":188,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/posts\/187\/revisions\/188"}],"wp:attachment":[{"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/media?parent=187"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/categories?post=187"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thibaultklein.com\/ios\/wp-json\/wp\/v2\/tags?post=187"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}