<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Valerii Che on Medium]]></title>
        <description><![CDATA[Stories by Valerii Che on Medium]]></description>
        <link>https://medium.com/@myltik?source=rss-ddeb906ee2b1------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*fAwM7Ad4ZbLO6tjijb0WtA.jpeg</url>
            <title>Stories by Valerii Che on Medium</title>
            <link>https://medium.com/@myltik?source=rss-ddeb906ee2b1------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 21:48:04 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@myltik/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Server-provided animations in iOS apps]]></title>
            <link>https://medium.com/bumble-tech/server-provided-animations-in-ios-apps-b51ce63beff3?source=rss-ddeb906ee2b1------2</link>
            <guid isPermaLink="false">https://medium.com/p/b51ce63beff3</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[animation]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Valerii Che]]></dc:creator>
            <pubDate>Thu, 17 Jan 2019 10:39:25 GMT</pubDate>
            <atom:updated>2019-07-11T13:36:08.095Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/1*MHjBoelVi1DYPgjBsmcBOA.png" /></figure><p>Hi everyone! About six months ago we launched one of Badoo’s most exciting features: <a href="http://badoo.live/">Live Streaming</a>. One of its main functionalities is that viewers can send gifts to their favourite streamers to express their appreciation. We wanted to make the gifts as fancy and as engaging as possible, so it was decided to make some of them really lively, and by this I mean animated. And to engage people even more, we, the Badoo team, planned to update those gifts and animations every few weeks.</p><p>As an iOS engineer, you might have already guessed the challenge we faced here: the need to add new animations and remove the old ones was going to require a fair amount of work from the client side. We’d need both the Android and the iOS development teams for every release — which, when combined with the amount of time App Store reviews and approval often take, would mean it might be days before each update could go live. But we solved the problem, and I’m going to explain to you how.</p><h3>Solution overview</h3><p>By this stage, we already knew how to <a href="https://badootech.badoo.com/behind-the-scenes-with-importing-adobe-after-effects-animation-into-badoo-ios-app-45a21e2ba1e4">export Adobe After Effects (AAE) animations into the format readable by our iOS app</a> using the Lottie library. This time though, we went a bit further: we decided to create a kind of animation storage service, available via the internet. In other words, we would store all the actual animations on the server and deliver them to the client apps on demand:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/828/0*NE9UlWzHxuMYdy-C" /></figure><p>Here is what the final solution looks like in the iOS simulator on the developer’s machine:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/372/1*HVKtV6EOC40Zdn3B10PA2g.gif" /></figure><p>However, in this post, the example I’m going to use is a very simple animation that I created myself. It’s not as fancy as Badoo’s one, but it’s good enough to demonstrate the potential of the described approach.</p><h3>Exporting animations</h3><p>The Adobe After Effects (AAE) project of animations I’m using here can be found along with other <a href="https://github.com/chupakabr/server-provided-animations">source files on github</a>. So, after opening the AAE animation project located in <em>_raw/animations/Fancy/Fancy.aep</em>, you should see a window like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JUBbbCEFv5SV-kzv" /></figure><p>At this point, I’m not going to go into how animations are being created in AEE, but what I’m going to explain is how to import already existing animations from AAE into an iOS app-readable format using the <a href="https://airbnb.io/lottie/after-effects/bodymovin-installation.html">Bodymovin plugin</a>.</p><p>Having made sure the plugin is installed, open it by selecting the Window/Extensions/Bodymovin option in the menu:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3QhDjotpLAGyXLgM" /></figure><p>Now you should see the Bodymovin window where you can select the animation you wish to export, specify the output file path and then open export settings:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Qu8g8ui2x9LGLTQU" /></figure><p>Having selected and opened animation settings, we can now ask Bodymovin to embed the assets into the resulting JSON file by checking the Assets / Include in json option:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dmwGGMSNwVX_NE6v" /></figure><p>Finally, the selected animation composition is exported and saved to the specified file by clicking the Render button.</p><h3>Storing animations on the server</h3><p>Let’s assume we have moved our rendered animations JSON files onto our preferred web server via the Internet. In our case, for simplicity’s sake, I’ve uploaded them into this project’s github repository. The animations are available here:</p><ul><li><a href="https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/clouds.json">Clouds animation</a></li><li><a href="https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/fireworks.json">Firework animation</a></li></ul><p>Base URL:</p><ul><li><a href="https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/">https://raw.githubusercontent.com/chupakabr/server-provided-animations/master/_raw/rendered-animations/</a></li></ul><p>Animation-specific IDs:</p><ul><li>clouds.json</li><li>fireworks.json</li></ul><blockquote><em>Note: Looking for an animations provider web server written in Swift? Find the solution </em><a href="https://github.com/chupakabr/server-provided-animations/tree/master/Server"><em>here on github</em></a><em> and a detailed explanation in </em><a href="https://medium.com/@myltik/rest-api-with-swift-on-vapor-fca5ea6667f"><em>this article</em></a><em>.</em></blockquote><p>At this point, we have a fully-functional animations-provider server, so it’s time to move onto the most exciting part: presenting the animations to our users.</p><h3>Fetching and presenting animations</h3><p>At this point I strongly recommend opening our example iOS app project located at <em>Client/ServerProvidedAnimation.xcworkspace</em> as it already has all the necessary boilerplate code and configurations.</p><h3>Loading animations data</h3><p>Given that the REST API endpoints for obtaining animation data are now up and running, it’s time to introduce the data provider protocol and add its server implementation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/67ef645d02d7dca0ffd715c21482fe89/href">https://medium.com/media/67ef645d02d7dca0ffd715c21482fe89/href</a></iframe><p>This data provider class allows us to load animations from the server in JSON format on demand and hold them in memory for rendering on the UI. Assuming we are following the MVVM pattern, it can easily be used in the ViewModel entity in the following way:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f022b91ab1622357acfbec5ae1f74d09/href">https://medium.com/media/f022b91ab1622357acfbec5ae1f74d09/href</a></iframe><p>The ViewModel updates the selected animation data property when it receives a valid HTTP response from the server with a non-empty JSON object inside. This data is used by the presentation layer to schedule the animation rendering.</p><h3>Presentation layer</h3><p>Now we can use our ViewModel to access the animation data and present it via the UI in the “on tap” action handler attached to the button:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5f531650b886bfaaf6ad131bd480d7b1/href">https://medium.com/media/5f531650b886bfaaf6ad131bd480d7b1/href</a></iframe><p>Basically, what we have here is a button handler which triggers an update of the LOTAnimationView instance with the most recent animation data coming from the ViewModel.</p><p>Here’s what the final result looks like:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/300/1*7rZ7XMLpiULZPxarjen13Q.png" /></figure><p>That’s pretty much it. Animations are now being loaded from the prepared REST API endpoint and rendered on the client on demand.</p><h3>Tips &amp; Limitations</h3><p>Tips and tricks:</p><ul><li>AAE allows the use of most asset types including raster and vector graphics;</li><li>Bodymovin makes it possible to embed all assets into an output JSON animation file (using base64 encoding) — this means we can avoid separate assets loading on the client side;</li><li>For the animations, you have the choice between drawing straight into the vector in AAE, or simply importing Adobe Illustrator vector graphics.</li></ul><p>Unfortunately, it’s not yet possible to import SVG vector graphics into AAE (I’ve tried!).</p><blockquote>More tricks and potential problems are described in this <a href="https://badootech.badoo.com/behind-the-scenes-with-importing-adobe-after-effects-animation-into-badoo-ios-app-45a21e2ba1e4">amazing article</a> written by my colleague <a href="https://medium.com/u/58fc12aa94bb">Radoslaw Cieciwa</a>.</blockquote><h3>Conclusions</h3><p>So, what does using server-provided animations give us? The most obvious benefit of this approach is the ability to decouple all stakeholders of the animations update flow. In other words, to release a fancy new animation, all designers have to do is to provide the animation’s JSON representation to the server team. And to remove one, the server team just has to remove that particular animation from the discovery service. No time wasted!</p><p>Another cool thing is that the same functionality can be implemented on all supported client platforms (iOS, Android, Web,..) without having to adjust the existing server functionality or raw animations.</p><p>That’s it for today! Thanks for reading 🙂</p><h3>Resources</h3><ul><li>“<a href="https://badootech.badoo.com/behind-the-scenes-with-importing-adobe-after-effects-animation-into-badoo-ios-app-45a21e2ba1e4">Behind the scenes with importing Adobe After Effects animation into Badoo iOS app</a>” by <a href="https://medium.com/u/58fc12aa94bb">Radoslaw Cieciwa</a>;</li><li><a href="https://github.com/airbnb/lottie-web/blob/master/build/extension/bodymovin.zxp">Bodymovin plugin for AAE</a> by <a href="https://medium.com/u/ebe93072cafd">AirbnbEng</a>;</li><li>Full project is available <a href="https://github.com/chupakabr/server-provided-animations">here on github</a>;</li><li><a href="https://airbnb.io/lottie/after-effects/bodymovin-installation.html">Installing bodymovin plugin for AAE</a> by <a href="https://medium.com/u/ebe93072cafd">AirbnbEng</a>;</li><li><a href="https://github.com/airbnb/lottie-ios">Lottie iOS library</a> by <a href="https://medium.com/u/ebe93072cafd">AirbnbEng</a>;</li><li>“<a href="https://medium.com/@myltik/rest-api-with-swift-on-vapor-fca5ea6667f">REST API with Swift on Vapor</a>” by <a href="https://medium.com/u/ddeb906ee2b1">Valerii Che</a>vtaev;</li><li><a href="http://aescripts.com/learn/zxp-installer/">ZXP plugin installer</a> for AAE.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b51ce63beff3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/bumble-tech/server-provided-animations-in-ios-apps-b51ce63beff3">Server-provided animations in iOS apps</a> was originally published in <a href="https://medium.com/bumble-tech">Bumble Tech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[REST API with Swift on Vapor]]></title>
            <link>https://medium.com/@myltik/rest-api-with-swift-on-vapor-fca5ea6667f?source=rss-ddeb906ee2b1------2</link>
            <guid isPermaLink="false">https://medium.com/p/fca5ea6667f</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[vapor]]></category>
            <category><![CDATA[rest-api]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[server-side-swift]]></category>
            <dc:creator><![CDATA[Valerii Che]]></dc:creator>
            <pubDate>Sun, 13 Jan 2019 13:01:50 GMT</pubDate>
            <atom:updated>2019-01-13T13:01:50.923Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Vh-lu3_KsP0GHryFYrOb6A.jpeg" /></figure><p>Good day everyone!</p><p>Recently I was in need to have a server-side storage with some kind of a discovery service for my JSON data files. So I was tearing myself apart:</p><ul><li>One part of me, as a server-side engineer, was pushing towards having the files stored on Amazon S3 with one more JSON file as a discovery information for the available data;</li><li>Another part of me, as a client-side engineer on iOS, was craving to find some web server framework in Swift and play with it.</li></ul><p>After a bit of fighting with myself, I decided to come up with this post due to the following facts:</p><ol><li>Lately I’m mostly busy developing iOS apps in Swift;</li><li>I’m actually very keen to see how different is Swift on the server in comparison to more traditional server technologies like Java, JavaScript, etc.</li></ol><p>In this post I’m going to implement a simple REST API web server which is able to provide JSON data identified by unique ID, in our case a piece of data will be represented as an animation exported from Adobe After Effects (AAE) as JSON (read as “some JSON object”).</p><p>So let’s begin!..</p><h3>Preparation</h3><p>After having a quick read of <a href="https://www.netguru.co/codestories/server-side-swift-frameworks-comparison">this quite interesting article</a> about most popular Swift based web frameworks such as <a href="https://www.kitura.io/">Kitura</a>, <a href="https://perfect.org/">Perfect</a> and <a href="https://vapor.codes/">Vapor</a>, I decided to go with the latter one due to its rapid development nature aka Ruby on Rails and active community around it. Mind though — I don’t say it’s the best choice.</p><p>So let’s create an empty Vapor project. First we need to install Vapor framework and its command line tools following <a href="https://docs.vapor.codes/3.0/install/macos/">this guidelines</a>.</p><p>After we have Vapor installed, creating new project is simple as running the following command in Terminal:</p><p><em>$ vapor new AnimationsProviderServer</em></p><p>It’s also useful to generate Xcode project for easier development of our server:</p><p><em>$ vapor xcode</em></p><p>At this point we should have Xcode project ready to be opened and even ran!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/618/0*zK9iGnZYo0O1UZeW" /></figure><p>The server will be available on default 8080 port, so you can open “<a href="http://localhost:8080/">http://localhost:8080</a>” URL in your browser and check if it works.</p><p><em>Short remark</em>: Vapor doesn’t support “hot reload” feature out of the box at the moment of writing this article, but it’s possible to set this up via gulp-vapor package available <a href="https://www.npmjs.com/package/gulp-vapor">here on NPMJS</a>.</p><p>Voila, now let’s code a little bit!</p><h3>Data model</h3><p>Now it’s time to add some logic to the server. Let’s create a model entity to hold information about our animations, for now everything we need to represent an animation is to have its identificator and JSON data exported from Adobe After Effects (AAE). So the animation model may look like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c44b718acb8ce58f26f8ff654ef0d085/href">https://medium.com/media/c44b718acb8ce58f26f8ff654ef0d085/href</a></iframe><p>Next we need to import animations into the project, to do so simply drag and drop JSON files exported from AAE into Resources folder of the server Xcode project, the project hierarchy should look like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/584/0*uXN8cPt7LXrDNibb" /></figure><p><em>Note: Make sure the imported JSON files are added to the “App” target.</em></p><h3>Data storage</h3><p>Somehow we need to access imported animations resources, to achieve that we may want to implement some kind of a storage entity, let’s call it AnimationsStorage:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/01d46788e47488236442d283d968e7ae/href">https://medium.com/media/01d46788e47488236442d283d968e7ae/href</a></iframe><p>In order to make AnimationsStorage service available in Vapor controllers, we should register it in <em>configure.swift</em> file:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f080752ab12b1404822d7b56ba7f97e0/href">https://medium.com/media/f080752ab12b1404822d7b56ba7f97e0/href</a></iframe><p>Basically, treat <em>configure.swift</em> file as source of information about all available global services, utilities, etc.</p><h3>REST API</h3><p>Next let’s create a simple controller which returns requested animation by ID as JSON via HTTP GET:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6f5c94ad0b54bf2b7fcbd1e526190564/href">https://medium.com/media/6f5c94ad0b54bf2b7fcbd1e526190564/href</a></iframe><p>The last step for the server project is to add required routing rules, so the animations are accessible via HTTP. Vapor framework has a separate file for specifying routing tables called <em>routes.swift</em>, in our project it should look similar to this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b6d1e0033f03d74885bd3ec422c6c26b/href">https://medium.com/media/b6d1e0033f03d74885bd3ec422c6c26b/href</a></iframe><p>Now we have fully working animations provider server, which could be requested by URL via HTTP GET, for instance:</p><ul><li>Fireworks: <a href="http://localhost:8080/animation/fireworks">http://localhost:8080/animation/fireworks</a></li><li>Clouds: <a href="http://localhost:8080/animation/clouds">http://localhost:8080/animation/clouds</a></li></ul><p>Requesting unavailable animation will result in 404 HTTP code with an empty body.</p><p><em>Note: at this point you may want to restart the web server to make all the changes we’ve made to the code available via REST API.</em></p><h3>Conclusions</h3><p>So we made it to the end! We’ve gone through the process of creating Vapor project from scratch, adding some business functions to the server, deploying and making it available via HTTP.</p><p>I wouldn’t say that Swift on Vapor sold me the idea of using it for implementing server solutions after I got to know with such server oriented technologies like Java and Go. But Swift is evolving, and evolving fast, so I’m very curious to see how it will pass the test of time, and what business applications Swift will have apart of client-side development for Apple platforms.</p><p>Meanwhile to me it looks like Swift on Vapor is a great starting point for those iOS/macOS engineers who want to become more familiar with server development concepts using the language they are already familiar with.</p><p>Thanks for your attention :)</p><h3>Resources</h3><ul><li>“Hot reload” with <a href="https://www.npmjs.com/package/gulp-vapor">gulp-vapor</a>.</li><li>Server source code is available <a href="https://github.com/chupakabr/server-provided-animations/tree/master/Server">here on github</a>;</li><li><a href="https://www.netguru.co/codestories/server-side-swift-frameworks-comparison">Server-side Swift Frameworks Comparison</a> by Robert Abramczyk;</li><li><a href="https://docs.vapor.codes/3.0/">Vapor documentation</a>;</li><li><a href="https://vapor.codes/">Vapor framework</a>.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fca5ea6667f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Managing Big Data]]></title>
            <link>https://medium.com/@myltik/managing-big-data-9b36f9df12b?source=rss-ddeb906ee2b1------2</link>
            <guid isPermaLink="false">https://medium.com/p/9b36f9df12b</guid>
            <category><![CDATA[hadoop]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[logstash]]></category>
            <category><![CDATA[blog]]></category>
            <category><![CDATA[big-data]]></category>
            <dc:creator><![CDATA[Valerii Che]]></dc:creator>
            <pubDate>Sat, 01 Dec 2018 17:25:02 GMT</pubDate>
            <atom:updated>2018-12-01T17:25:02.833Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gqnglTOa6qZH6Z3Qntkn2A.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/wloRJGS6Y34?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Florian Pérennès</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Hey there!</p><p>About 3 years ago from now, at my previous job, I had an opportunity to solve very interesting and to some extent complex problem: implement a solution for processing and analysing <strong>Big</strong> amounts of <strong>Data</strong> on daily basis, providing all the needed information to our higher management on demand. Here by “Big amounts of Data” I mean the average value of 1 TB of raw data per day.</p><h3>First solution</h3><p>At first, we implemented non real time solution utilising the power of <a href="https://hadoop.apache.org/">Hadoop</a> and <a href="https://hive.apache.org/">Hive</a> (HiveQL) via <a href="https://aws.amazon.com/">Amazon Web Services</a> (AWS). By that time we already had most of our services deployed on AWS, so we decided to go with Amazon this time again.</p><p>The main idea was to feed raw data stored on <a href="https://aws.amazon.com/s3/">S3</a> into HDFS (Hadoop), then run HiveQL queries on that data to generate required data reports and then wipe the whole thing out as the maintenance costs of running Hadoop cluster was quite high and there is no need to keep it alive anyway.</p><p>The solution was solving the business problem we had initially, but in the end we had to play around the running costs of <a href="https://aws.amazon.com/emr/">EMR</a> and <a href="https://aws.amazon.com/ec2/">EC2</a>, as Hadoop was quite pricey at that time for us. We even ended up reducing more than 70% of costs by using <a href="https://aws.amazon.com/ec2/spot/">Spot instances</a> (basically, marketplace of EC2 instances with huge discounts).</p><h3>New solution</h3><p>Half a year passed and we’ve encountered a problem that the approach we have is not sufficient anymore and the price tag of generating daily reports was too high, so we started to investigate other options.</p><p>We ended up implementing the new solution using a mix of production ready (like <a href="https://aws.amazon.com/redshift/">Redshift</a>) and green technologies (like <a href="https://aws.amazon.com/kinesis/">Kinesis</a>) hosted on AWS. This time the main idea was the following: continuously feed raw data into Amazon Kinesis streams which were able to convert that raw data into the meaningful format and pass it into Redshift via Kinesis Firehose component, so then we can run SQL queries in real-time directly on Redshift (which AFAIK is PostgreSQL database optimised for large amounts of data).</p><p>During implementation, we even had a chance to contribute to Open Source community by implementing <a href="https://github.com/chupakabr/logstash-output-firehose">Logstash output plugin for Amazon Kinesis Firehose</a> as well as to research some other interesting Big Data Warehouse technologies like <a href="https://www.snowflake.com/">Snowflake</a>.</p><p>The first version of the new solution and its first customer integration took us less than 3 months overall. The price in comparison to the first solution was more or less on the same level, but the benefits we’ve got in terms of usability, availability and maintenance did overweight the initial implementation significantly.</p><h3>Why?</h3><p>No doubt many things has changed since then, but nevertheless it was real fun and great experience for me.</p><p>I think that one of the most exciting parts of being a software engineer is that you are not limited to any particular tech stack and can always solve the same problem in many different ways using completely unrelated technologies, either open source or proprietary.</p><p>I believe that the essential thing in software engineering is to have the desire to explore and don’t be afraid of the domain not yet discovered by you.</p><p>Cheers!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9b36f9df12b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making custom designable UI components]]></title>
            <link>https://medium.com/bumble-tech/making-custom-designable-ui-components-2527be1a0c19?source=rss-ddeb906ee2b1------2</link>
            <guid isPermaLink="false">https://medium.com/p/2527be1a0c19</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[ui-design]]></category>
            <category><![CDATA[ui]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Valerii Che]]></dc:creator>
            <pubDate>Wed, 01 Aug 2018 10:49:33 GMT</pubDate>
            <atom:updated>2019-07-23T10:50:29.275Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CdhlEVpPbxjcKCOzYfrrDw.jpeg" /></figure><p>Hi there! I’m Valera, iOS Padawan at Badoo. Here in our company we are crazy about UI and spend plenty of time designing, polishing and improving the user interface to make our users happy, not only about the services we provide, but also about the look and feel of the app in general. At the end of the day, you don’t go to your first date or an interview in your pyjamas, but instead you would make sure that you wear a suit, or at least something smart/casual and presentable.</p><p>First, I want to mention that in Badoo we prefer to build UI in the code. This approach has its own pros and cons, but it’s not the topic of this post. Today I want to talk about building custom UI components, which is tightly coupled with the opposite approach of building UI — via Interface Builder (IB). Depending on your project, you may want to have some custom reusable UI components to be available for you in IB, to play with your UI component parameters without compiling the project and so on. And here I’m going to show you how to achieve that.</p><p>You can check out the full source code of the example project <a href="https://github.com/chupakabr/DesignableComponentExample">here</a>, or just create an empty project of your own to follow up with the steps below. However, I will be skipping the code snippets for views creation and constraints, so the full source code is worth checking.</p><h3>The idea</h3><p>Let’s create a simple UI component for our example app to present some information text. The component should reveal a link when a user taps on it. It should have some basic IB configurable properties like border style, texts, colours, and so on.</p><h3>Designable class</h3><p>It’s very simple. To create a custom component you just need to create a new class, extend it from UIControl (in our example I extended from UIView for simplicity) and add @IBDesignable annotation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/088bd4ad29cb7833a428122a9daf701f/href">https://medium.com/media/088bd4ad29cb7833a428122a9daf701f/href</a></iframe><p>Then add your inspectable properties [a property which a user of your component can change in IB]:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/17c7b50f9885af03ebd756610723774e/href">https://medium.com/media/17c7b50f9885af03ebd756610723774e/href</a></iframe><h3>Using your component in IB</h3><p>Now, it’s time to test this new UI component in IB. To do so, just drag&amp;drop a “view” from the IB Object library to the main view and then add minimal constraints such as position, width, height:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/0*cgPXXZKK-XyJ1iMY." /></figure><p>Then set the UIView’s custom type to the one we created before, i.e. MyDesignableComponent:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/0*dt16OZ_BJeX4uEn1." /></figure><p>And voilà! Now we can see <em>borderWidth</em> property within our view’s properties in the Attributes Inspector:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/0*ruTcL3simHOL9RnG." /></figure><p>You probably noticed that if you change a value of <em>borderWidth</em> in IB it won’t do anything, and that’s because we didn’t bind any logic to it, so let’s fix that and update <em>borderWidth</em> property implementation in the code to the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dae595ab4f5183ec93b45b97ace4df5e/href">https://medium.com/media/dae595ab4f5183ec93b45b97ace4df5e/href</a></iframe><p>Now compile the project, open IB and try to change the <em>borderWidth</em> property to some positive number — there you go! Now the border is visible:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*nkHs2jfpG48ZKZ0V." /></figure><p>In similar way we can add more properties like border colour:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bc21839188a29f4cd9470d260525a60d/href">https://medium.com/media/bc21839188a29f4cd9470d260525a60d/href</a></iframe><p>We also can add some text properties with a default values like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3b3158d540801709689b9641b7772906/href">https://medium.com/media/3b3158d540801709689b9641b7772906/href</a></iframe><p>Simple, isn’t? And that’s pretty much it!</p><p>Now, after just a few more minutes of work we have a component like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*C6HWQSxQdyIaIwv8." /></figure><p>And here’s what this component configuration looks in IB:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/855/0*6TteYMGsfP3hlDfS." /></figure><h3>Some tips</h3><p>Sometimes you may need to have an inspectable property for UI designing only, for example you want to see what the “expanded state” of your control will look like in IB. In order to achieve that, you need to wrap the block of code in the preprocessor macro #if TARGET_INTERFACE_BUILDER .. #endif</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bd1d54b0219a9b9a71b1de2012fd550a/href">https://medium.com/media/bd1d54b0219a9b9a71b1de2012fd550a/href</a></iframe><p>As an option, it’s also possible to prepare your custom UI control specifically for IB by overriding the <a href="https://developer.apple.com/documentation/objectivec/nsobject/1402908-prepareforinterfacebuilder">prepareForInterfaceBuilder</a> method in your class.</p><p>And never forget to update the related view’s state upon @IBInspectable property change to see the result in IB right away, like we did in the <em>borderWidth</em> and <em>borderColor</em> didSet implementations.</p><h3>Limitations</h3><p>Designable components have some limitations. For example, you can only mark a limited set of types as @IBInspectable, which means you cannot have an inspectable enum or array of Strings property.</p><p>Another potential downside of @IBDesignable components is that in order to reflect the latest changes in a designable component’s implementation, a project rebuild is required (Xcode does this automatically in the background). So, this could be a decisive factor for big projects. A fair solution for this issue might be a separate project for UI components.</p><p>Designable components are not limited by UIView, and again, you can extend from UIControl and take full control of your component’s rendering and laying out.</p><h3>Conclusions</h3><p>In general, I think UIKit gives developers a lot of flexibility in implementing UI. For instance, @IBDesignable components could simplify UI development as they give a developer the ability to set up UI in Storyboard, playing with various parameters without recompiling a project.</p><p>So, depending on your workflow and needs, I think, this approach might be useful for you, but if not — no problem, at least you know your options!</p><p>Thanks for reading!</p><p>Cheers.</p><h3>Resources</h3><p>The full project is available here: <a href="https://github.com/chupakabr/DesignableComponentExample">https://github.com/chupakabr/DesignableComponentExample</a></p><p>Detailed reference by Apple: <a href="https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementingACustomControl.html">https://developer.apple.com/library/content/referencelibrary/GettingStarted/DevelopiOSAppsSwift/ImplementingACustomControl.html</a></p><p>Preparation of UI for IB: <a href="https://developer.apple.com/documentation/objectivec/nsobject/1402908-prepareforinterfacebuilder">https://developer.apple.com/documentation/objectivec/nsobject/1402908-prepareforinterfacebuilder</a></p><p>What’s new in Xcode 6: <a href="https://developer.apple.com/videos/play/wwdc2014/401/">https://developer.apple.com/videos/play/wwdc2014/401/</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2527be1a0c19" width="1" height="1" alt=""><hr><p><a href="https://medium.com/bumble-tech/making-custom-designable-ui-components-2527be1a0c19">Making custom designable UI components</a> was originally published in <a href="https://medium.com/bumble-tech">Bumble Tech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[iOS UI development in Badoo]]></title>
            <link>https://medium.com/bumble-tech/ios-ui-development-in-badoo-592d76dc5b37?source=rss-ddeb906ee2b1------2</link>
            <guid isPermaLink="false">https://medium.com/p/592d76dc5b37</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ui]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <dc:creator><![CDATA[Valerii Che]]></dc:creator>
            <pubDate>Wed, 01 Aug 2018 10:49:25 GMT</pubDate>
            <atom:updated>2018-08-28T15:33:38.765Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*o8DIYJBiSgLUoB_G" /></figure><p>Hey! Being a developer in Badoo is not only interesting and fun, but also challenging — you have to produce highly maintainable code in a short period of time. Due to the amount of new features coming to our team on a weekly basis, we have to think of the architecture in the first place, otherwise it will be impossible to add new functionality to the app without breaking existing features later. Obviously this also applies to UI implementation whether it’s done via code, xib or using a mixed approach. In this post I’m going to describe some of the UI implementation techniques we use here in Badoo, which make UI development easier, more extensible and testable for our team.</p><h3>Before we start…</h3><p>As a starting point for this article I’ll be using a sample app written in Swift to demonstrate UI implementation techniques. The app shows a list of friends upon a button click. It also consists of the following three domains:</p><ol><li>Components — custom UI components, which means UI related code only;</li><li>Demo app — demo view models and other entities which have only UI-related dependencies;</li><li>Real app — view models and other entities which also may contain domain specific logic and dependencies.</li></ol><p>Why such separation, you may ask? I’ll give you the answer in just a few moments. For now, take a quick look at the UI of the sample app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*Mo20D8Rc1fwL79IW" /></figure><p>This is a popup view with content on top of the full-screen view. Simple as it is. <br>The full source code of the example project is worth checking and is available <a href="https://github.com/chupakabr/ios-ui-techniques-example">on github</a>.</p><h3>Value observing utility</h3><p>Before we dig deeper into the UI code, I want to present one utility class which I’m using in the sample app — <em>Observable</em> and its interface looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a6fb425cfc817d0ea531ae277b5bb196/href">https://medium.com/media/a6fb425cfc817d0ea531ae277b5bb196/href</a></iframe><p>What it does, is simply notify all previously subscribed observers about the changes in the stored value, so it’s kind of an alternative to KVO observing or Reactive observables if you wish. Here is a usage example:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9c81fb86702e878cc294f2df367dbe35/href">https://medium.com/media/9c81fb86702e878cc294f2df367dbe35/href</a></iframe><p>This code subscribes to the changes in <em>self.viewModel.</em>items property and when there’s a change, the observer closure executes some business logic like updating the view’s state and reloading collection view data with new items.</p><p>You will see more usages of this utility class later in this post, but now you are prepared!</p><h3>Here we go: the techniques</h3><p>So the fun starts here, in this section I’ll present four UI development techniques we use here in Badoo which are:</p><ol><li>Implement UI in the code;</li><li>Use layout anchors for simplicity;</li><li>Divide and conquer with components;</li><li>UI and logic separation.</li></ol><p>I have to say that the second one is not crucial, but it’s still good to know about the existence of this technique. So let’s dig in…</p><h3>#1: Implement UI in the code</h3><p>Here in Badoo, we implement most of the UI in the code. You may ask why we don’t use XIBs or Storyboards, and it’s a fair question. In short, the reasoning for this approach is the maintainability of the code in a medium-large team, and this includes:</p><ul><li>Clear changes in the code, and so clearer code reviews, which means there is no need to parse the XML of a Storyboard / XIB file looking for the changes made by your team mate;</li><li>It’s much easier for Version Control Systems like GIT to work with the code instead of heavyweight XML files, especially during merge conflicts, also considering that XIB / Storyboard file content is being changed on every file save, even when the UI wasn’t changed at all (I heard this should have been fixed in Xcode 9, but I still get this problem from time to time);</li><li>It could be hard to change and maintain some properties in Interface Builder (IB), like layer properties upon subview layout for example, and this may lead to a multiple sources of truth of a view’s state;</li><li>Interface Bulider is not the fastest tool really, and sometimes it’s much faster to navigate through the code instead. Or maybe it’s just me? 🙂</li></ul><p>Take a look at the following view controller (FriendsListViewController):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e29c7b763e4f6f005ab0a5988005a484/href">https://medium.com/media/e29c7b763e4f6f005ab0a5988005a484/href</a></iframe><p>In this example you can see that it’s only possible to instantiate this view controller by providing its view model and view config entities. If you want to know more about view models, i.e. MVVM design pattern, you can read about it here <a href="https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52">on medium</a>. While a view’s config is a simple struct entity which defines a view’s layout and style, like inset, sizes, colors, fonts, etc. I think it’s also a good practice to provide some default view configuration similar to this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/53ea7ed438a2263645ed382c0145607f/href">https://medium.com/media/53ea7ed438a2263645ed382c0145607f/href</a></iframe><p>All view initialization is done in the <em>setupContainerView</em> method which is called only once upon view creation, basically just adding all needed subviews to the view’s hierarchy here and then applying their layouts and styles.</p><p>Now check out that view controller’s presentation entity:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2913f4fccd0f7fa64d913ce0134fa2b0/href">https://medium.com/media/2913f4fccd0f7fa64d913ce0134fa2b0/href</a></iframe><p>You can see responsibility separation clearly here, and it’s not any more complicated than triggering a segue from a storyboard really.</p><p>The creation of the view controller is pretty straightforward given you have its view model set up and are just using the default view configuration:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9cf39d1808a6c8179193e06a0561e0da/href">https://medium.com/media/9cf39d1808a6c8179193e06a0561e0da/href</a></iframe><p>Now let’s have a closer look at the magic happening in the layout code..</p><h3>#2: Use layout anchors for simplicity</h3><p>Here is the view’s layout code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c552b2d8683312dcf02135f495842c9a/href">https://medium.com/media/c552b2d8683312dcf02135f495842c9a/href</a></iframe><p>Simply what this code does is lay out <em>infoView</em> inside its superview at (0;0) origin nesting a superview’s size.</p><p>So why are we using layout anchors? It’s just short and simple. Obviously you can use frame-based layout and calculate all the positions and sizes on the fly, but that just can get quite messy sometimes. You can also use in-code text layout constraints as described <a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ProgrammaticallyCreatingConstraints.html#//apple_ref/doc/uid/TP40010853-CH16-SW1">here</a>, but it’s impossible to use a safe-area layout guide, because this is also an error prone approach and you have to remember the text format as well:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/eb9aee5840574fe7996386342c3c028a/href">https://medium.com/media/eb9aee5840574fe7996386342c3c028a/href</a></iframe><p>It’s quite easy to make a mistake or have a typo in the text string defining the layout in the example above, isn’t it?</p><h3>#3: Divide and conquer with components</h3><p>As you can see, the UI of the sample project is split into components, each of which does one particular function and no more. Take a look at the following view from the sample project:</p><ol><li>FriendsListHeaderView — a view which displays some information about friends and a close button;</li><li>FriendsListContentView — a view that displays a friends list with clickable cells, more content is dynamically loaded upon reaching the end of the list;</li><li>FriendsListView — a container view for the header and the content views, which lays out the latter two on the screen.</li></ol><p>I personally love this single responsibility approach, as you always know which exact entity is responsible for each particular function. It helps a lot, not only during bug fixing times (which you probably not a big fan of), but even when you develop a new feature, as this approach also significantly increases the reusability level of the code.</p><h3>#4: UI and logic separation</h3><p>And last but not least, my favourite high level technique, which saved a lot of time and nerves for our team, is UI and logic separation. Literally, what we have in place is a separate project for all UI components, and another project for business logic and the glue parts of UI and logic components.</p><p>Let’s take a look at the sample project. As you will remember, we have our presenter implementation looking like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aa42274de29fed55063e5d91d5188fa4/href">https://medium.com/media/aa42274de29fed55063e5d91d5188fa4/href</a></iframe><p>As you can see, you need to provide only a header and a content view models. The rest is hidden inside the UI components’ implementation that I described above. A header view model protocol in the sample project looks like this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0b8eaf7d8065a50ab9adced3be2c35fe/href">https://medium.com/media/0b8eaf7d8065a50ab9adced3be2c35fe/href</a></iframe><p>Now imagine you are going to add some Visual Tests for your UI, and I can tell you — it’s as simple as passing stub view models for your UI components:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8a7083fe420369d4a1a890064b3a890a/href">https://medium.com/media/8a7083fe420369d4a1a890064b3a890a/href</a></iframe><p>Looks pretty straightforward and simple, doesn’t it? Now, we want to add some real business logic for our component in our app, which may require some data providers, raw data models and so on:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/7d575b3319ae8a0da8cc44da74c08ec2/href">https://medium.com/media/7d575b3319ae8a0da8cc44da74c08ec2/href</a></iframe><p>It couldn’t be easier: just implement the data provider and you are good to go!</p><p>This looks a bit more complicated with a content view model, but still responsibility separation makes the life so much easier. And that’s how to instantiate and present the friends list screen in the app upon a button click:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/8d28a6937c364bd1aa8440d4f43f06e7/href">https://medium.com/media/8d28a6937c364bd1aa8440d4f43f06e7/href</a></iframe><p>This technique helps to isolate the UI from its business, and even easily cover the whole UI with visual tests by feeding fake data to the components! So in my opinion, the separation of UI and related business logic is crucial for the success of a rapidly developing big project, whether it’s a startup or an already established product.</p><h3>Conclusions</h3><p>Obviously, this is just a set of some techniques we use in Badoo and I’m not saying it’s a silver bullet for all possible cases, so evaluate and use them if they fit your team and projects. Of course there are other techniques such as Designable UI Components alongside Interface Builder that I explained in <a href="https://medium.com/@chevtaev/2527be1a0c19">my other article</a>, which we try to avoid using at Badoo for maintainability reasons. Remember, everyone has their own opinion and a view of the big picture, so I believe in order to be successful you have to reach a consensus in your team and stick to a selected approach for most cases.</p><p>Thanks for your time and may the Swift be with you!</p><h3>Resources</h3><ul><li>Full project is available <a href="https://github.com/chupakabr/ios-ui-techniques-example">on github</a>;</li><li><a href="https://medium.com/@chevtaev/2527be1a0c19">Making custom designable UI components</a> by myself;</li><li><a href="https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52">iOS Architecture Patterns</a> by Bohdan Orlov, former Badoo developer;</li><li><a href="https://medium.com/@johnsundell/modelling-state-in-swift-3751a4acb8f3">Modelling state in Swift</a> by John Sundell;</li><li><a href="https://medium.com/@vinodhswamy/solid-principles-in-swift-7dc2b793fd68">SOLID Principles in Swift</a> by Vinodh Swamy;</li><li><a href="https://developer.apple.com/documentation/uikit/nslayoutanchor">NSLayoutAnchor</a> by Apple;</li><li><a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ProgrammaticallyCreatingConstraints.html#//apple_ref/doc/uid/TP40010853-CH16-SW1">Programmatically Creating Constraints</a> by Apple.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=592d76dc5b37" width="1" height="1" alt=""><hr><p><a href="https://medium.com/bumble-tech/ios-ui-development-in-badoo-592d76dc5b37">iOS UI development in Badoo</a> was originally published in <a href="https://medium.com/bumble-tech">Bumble Tech</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>