<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bornfight</title>
    <description>The latest articles on Forem by Bornfight (@bornfight).</description>
    <link>https://forem.com/bornfight</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F325554%2Fab09a0b3-9451-49fa-b549-4d1578f3c223.jpg</url>
      <title>Forem: Bornfight</title>
      <link>https://forem.com/bornfight</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bornfight"/>
    <language>en</language>
    <item>
      <title>MVP vs MVVM – choosing the right Android architecture</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Fri, 04 Sep 2020 07:48:33 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/mvp-vs-mvvm-choosing-the-right-android-architecture-3bmm</link>
      <guid>https://forem.com/bornfightcompany/mvp-vs-mvvm-choosing-the-right-android-architecture-3bmm</guid>
      <description>&lt;h2&gt;
  
  
  Software architecture is probably one of the most popular topics among developers, regardless of the platform you build for. With all the available frameworks and tools for asynchronous programming, dependency injection, networking, data caching and view-bindings, many patterns have evolved and some have stood out from the bunch.
&lt;/h2&gt;

&lt;p&gt;However, it is impossible to find the golden-gem of architecture that will fit everyone, especially if you’re trying to build a sustainable infrastructure as the core. The solution? Constant upgrades and enhancements to fit your needs the best. This story is all about that. It will delineate our transition from one pattern to another, elaborate why we replaced a well worked-out &lt;strong&gt;MVP&lt;/strong&gt; base for &lt;strong&gt;MVVM&lt;/strong&gt;, and how we did it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When starting a new project, we use our base (template) project as the ground floor. It contains all the elements we’ll certainly use to code an app:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it imports all the dependencies we’ll use in the project&lt;/li&gt;
&lt;li&gt;it sets up networking/caching/etc. libraries in advance&lt;/li&gt;
&lt;li&gt;it sets up the dependency injection graph&lt;/li&gt;
&lt;li&gt;it contains dozens of utils and helper classes for easier, cleaner and faster coding&lt;/li&gt;
&lt;li&gt;it enforces you to build upon the ground floor and work with the architectural pattern it’s set-up for&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_brozovic_timematerials_body01.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_brozovic_timematerials_body01.jpg" alt="Image: MVP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A BRIEF MVP IMPLEMENTATION OVERVIEW
&lt;/h3&gt;

&lt;p&gt;Our &lt;a href="https://gitlab.com/bornfight-mobile/android-public/androtemplate" rel="noopener noreferrer"&gt;MVP template project&lt;/a&gt; was created 5 years ago and has been constantly upgraded ever since. In our case, every screen we create (assuming there is a business logic) consists of three layers (the &lt;strong&gt;&lt;em&gt;Model&lt;/em&gt;&lt;/strong&gt;, the &lt;strong&gt;&lt;em&gt;View&lt;/em&gt;&lt;/strong&gt; and the &lt;strong&gt;&lt;em&gt;Presenter&lt;/em&gt;&lt;/strong&gt;) and a contract which binds them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;&lt;em&gt;View&lt;/em&gt;&lt;/strong&gt; should not contain any business logic and it should only manage the UI (for instance – bind views, programmatically set data which should be shown visually, handle click listeners, text watchers, animations etc.)&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;&lt;em&gt;Presenter&lt;/em&gt;&lt;/strong&gt; represents the layer which triggers the business logic classes, transforms and prepares the data for the View – basically, it is the middle man between the Model and the View&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;&lt;em&gt;Model&lt;/em&gt;&lt;/strong&gt; is responsible for database updates and/or web-server communication – it is a data provider.&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;&lt;em&gt;Contract&lt;/em&gt;&lt;/strong&gt; provides a list of methods which the View or the Presenter should implement – essentially, it enables communication between the two layers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MVP served us well through the years. It is an easy to follow design which deals well with the separation of logic. Unfortunately, it has some drawbacks which start to unfold as more code and more logic gets involved in the MVP triad.&lt;/p&gt;

&lt;h3&gt;
  
  
  MVP – THE DRAWBACKS
&lt;/h3&gt;

&lt;p&gt;The first problem is the &lt;strong&gt;&lt;em&gt;tight-coupling&lt;/em&gt;&lt;/strong&gt; between the View and the Presenter. Each View holds a reference to the Presenter and each Presenter holds a reference to the View. In order for the two layers to communicate, a &lt;strong&gt;&lt;em&gt;communication channel&lt;/em&gt;&lt;/strong&gt; has to be opened via the Contract. This approach results in &lt;strong&gt;&lt;em&gt;less-generic code&lt;/em&gt;&lt;/strong&gt; (since the Presenter can’t be used as a layer in the MVP triad for another View). In a heap of communication methods, both the View and the Presenter will &lt;strong&gt;&lt;em&gt;rapidly expand&lt;/em&gt;&lt;/strong&gt; in the code-line size. There is also an &lt;strong&gt;&lt;em&gt;extra layer of difficulty while writing unit tests&lt;/em&gt;&lt;/strong&gt;, since there is a View dependency in each Presenter.&lt;/p&gt;

&lt;p&gt;However, the biggest downside for us were the &lt;strong&gt;&lt;em&gt;UI updates&lt;/em&gt;&lt;/strong&gt;. In order to update a View component with data which has to be processed, the View must specifically be instructed by the Presenter. In other words, the View can’t &lt;strong&gt;&lt;em&gt;“automatically”&lt;/em&gt;&lt;/strong&gt; listen for the Model updates which the Presenter should expose. Therefore, &lt;strong&gt;&lt;em&gt;“auto”-UI updates&lt;/em&gt;&lt;/strong&gt; are hardly feasible. In order to succeed, we’d have to moderate the middle layer – the Presenter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_bubalo_blueprint_facebook-1024x536.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_bubalo_blueprint_facebook-1024x536.jpg" alt="Image: MVP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MVVM TO THE RESCUE!
&lt;/h3&gt;

&lt;p&gt;Luckily for us, there are many different sets of tools that can be used to bridge a View and a business logic layer in a more efficient way. It is only a matter of the concept which suits the architecture you want to tailor the most. In particular, to untangle all the hanks MVP tends to create, but simultaneously keep some of its benefits (easy to understand and build upon, easily maintainable etc.) we decided to go with MVVM and, among other things, with the&lt;a href="https://developer.android.com/topic/libraries/architecture" rel="noopener noreferrer"&gt;Android Architecture Components&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Moreover, by switching to MVVM, we were able to resolve all the issues mentioned above:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the View and the ViewModel (ex Presenter) are no longer tight-coupled&lt;/li&gt;
&lt;li&gt;the ViewModel code is more generic
with proper abstractions, we reduced the previously rapid growth of the files for complex screens&lt;/li&gt;
&lt;li&gt;the code is more testable&lt;/li&gt;
&lt;li&gt;the “auto”-UI updates are live&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  HOW THAT WORKS?
&lt;/h3&gt;

&lt;p&gt;Now, every screen consists of three layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;The View&lt;/em&gt;&lt;/strong&gt; – still only handles the UI actions, without any business logic involved in any of its responsibilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;The ViewModel&lt;/em&gt;&lt;/strong&gt; – handles the communication of the view with the rest of the application (calling the business logic classes) and exposes the states/data to whomever needs to consume it using LiveData&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;The Model&lt;/em&gt;&lt;/strong&gt; – a data provider that updates the database or communicates with a web-server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete flow is as follows: there is a View on top, which only has a dependency to (a) ViewModel(s). Since there is no longer a &lt;strong&gt;&lt;em&gt;one-to-one relationship&lt;/em&gt;&lt;/strong&gt; between the View and (formerly) the Presenter, it is now possible to couple multiple ViewModels to any View, since a ViewModel contains no View references. A ViewModel depends on repositories for fetching/caching data, and a repository will depend on a local and/or remote data source. In testing jargon, there is only one layer beneath the one you’re about to test, that you should mock (with the exception of a repository). Finally, since the states/data is exposed to its listeners via LiveData, we get &lt;strong&gt;&lt;em&gt;“auto”-UI updates&lt;/em&gt;&lt;/strong&gt; by simply observing it.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_anic_javakotlin_body01.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bornfight.com%2Fwp-content%2Fuploads%2F2019%2F08%2Fbornfight_blog_anic_javakotlin_body01.jpg" alt="Image: MVP"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  THE TRANSITION
&lt;/h3&gt;

&lt;p&gt;The idea for the transition did not come overnight. Moreover, we want our architecture to be perfectly balanced, so it’s powerful enough to satisfy the requests of highly-complex projects, and yet lightweight enough to be easily upgradeable and maintainable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;While creating the new skeleton, we kept up to the latter as the compass:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the architecture must leave us enough room to easily add up extra modules (e.g. UseCases etc.) for more complex projects, and it should be sufficient to build smaller and medium projects as is&lt;/li&gt;
&lt;li&gt;the structure we create must be easily testable&lt;/li&gt;
&lt;li&gt;the base set-up should not force us to create or update a large number of files before we even started to work on a screen itself&lt;/li&gt;
&lt;li&gt;we want to reduce boilerplate to minimum (e.g. RxJava calls etc.)&lt;/li&gt;
&lt;li&gt;we want a set of default actions to be present under the hood (e.g. default loader or displaying error messages, default schedulers etc.), but again, those actions must be easily overridable if necessary&lt;/li&gt;
&lt;li&gt;the code must be generic enough to fit all the cases we might encounter and easily adaptable if there is a case which is not directly supported by the foundations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a long list to cross, especially if you take into account all the MVP eyesores. We agreed on building a demo project where we’ll try to create the core which will obey our list the most. That project must be simple enough to let us easily experiment with the schemes we try to accomplish, yet robust enough to test all the standard application components (networking, local caching, etc). So, we made a forecast app. The process of putting the things together took about a month, considering all the projects we did aside. It included a lot of brainstorming and mutual consulting, since it’s sometimes hard to see the whole picture if you’re standing too close to the board. We are very pleased with the final result, and it worked very well for the tasks and the scenarios we’ve put it through so far.&lt;/p&gt;

&lt;p&gt;Is it perfect? Definitely not. Is it better than it used to be? We believe so. To discover the true advantages and, even more importantly, the disadvantages, we’ll have to build dozens of applications upon it, the same as we did with the MVP skeleton. One thing is certain – there is a plenty of brushing up and improvements our new base projects will have to go through, but we will do our best to maximize the benefits we gain from it – to fasten-up and boost our development speed, performance and quality. Having a base project as a starting point for every new application you make is extremely useful – if you have managed to set it up to be equally powerful as flexible. Besides performance boost, it appoints a well-designed standard you have to obey right from the start, which makes sure your code is consistent, clean and well-written.&lt;/p&gt;

&lt;h3&gt;
  
  
  CONCLUSION
&lt;/h3&gt;

&lt;p&gt;Is MVP bad? No. Is MVVM better? It depends. For our needs and the complexity of applications we create, MVVM should help us get rid off some drawbacks MVP entails. On the other hand, new drawbacks regarding MVVM will appear, and we have to be ready to ameliorate them since the benefits of a well-designed architecture will always surpass the disadvantages.&lt;/p&gt;

&lt;p&gt;If you are interested in how we assembled our new base project, stay tuned for the next blog which will explain it in detail.&lt;/p&gt;

&lt;p&gt;Until then, feel free to use our &lt;a href="https://gitlab.com/bornfight-mobile/android-public/androtemplate" rel="noopener noreferrer"&gt;MVP&lt;/a&gt; or &lt;a href="https://gitlab.com/bornfight-mobile/android-public/mvvmtemplate" rel="noopener noreferrer"&gt;MVVM&lt;/a&gt; template project as a free starting pack, depending on what you think suits you better.&lt;/p&gt;




&lt;p&gt;We’re available for partnerships and open for new projects. If you have an idea you’d like to discuss, &lt;a href="https://www.bornfight.com/contact/" rel="noopener noreferrer"&gt;share it with our team &lt;/a&gt;!&lt;/p&gt;

</description>
      <category>mvp</category>
      <category>mvvm</category>
      <category>android</category>
    </item>
    <item>
      <title>Case study: Building a companion mobile app for a cutting-edge media monitoring tool</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Thu, 04 Jun 2020 09:53:45 +0000</pubDate>
      <link>https://forem.com/bornfight/case-study-building-a-companion-mobile-app-for-a-cutting-edge-media-monitoring-tool-4pe7</link>
      <guid>https://forem.com/bornfight/case-study-building-a-companion-mobile-app-for-a-cutting-edge-media-monitoring-tool-4pe7</guid>
      <description>&lt;h2&gt;
  
  
  Changing the way companies do media intelligence
&lt;/h2&gt;

&lt;p&gt;Mediatoolkit is a 24/7 media monitoring and analytics tool that gathers information from 100+ million online sources. It notifies users in real time whenever their company, competitors, key people from their organisations or any other keyword they decide to track is mentioned online.&lt;/p&gt;

&lt;h1&gt;
  
  
  "Bornfight understands what does or doesn’t make sense for mobile users, so it’s no surprise that a lot of our users praised the new app’s intuitiveness and ease of use."
&lt;/h1&gt;

&lt;h5&gt;
  
  
  Antun Tomašević
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Mediatoolkit Product Manager
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Real-time tracking for on-the-go professionals
&lt;/h2&gt;

&lt;p&gt;Mediatoolkit’s web tool was upgraded with new functionalities much faster and much more frequently than the mobile version of their tool, so they tasked us with creating a new iOS and Android application from the ground up. One that would enable their customers to use all of Mediatoolkit’s core functionalities on-the-go.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vimeo.com/385017942"&gt;Mediatoolkit Mobile Application - Onboarding Animation&lt;/a&gt; from &lt;a href="https://vimeo.com/bornfight"&gt;Bornfight&lt;/a&gt; on &lt;a href="https://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Perfect companion app for a powerful web tool
&lt;/h2&gt;

&lt;p&gt;The goal of the project was not just to create a copy of the web version for mobile devices, but rather an application that complements the web tool. As Mediatoolkit’s core user group of PR professionals and marketers want to be aware of the communication surrounding their brand at all times, this mobile app enables them to get real-time notifications and keep track of all the news – even when they’re away from the computer.&lt;/p&gt;

&lt;h1&gt;
  
  
  "The main business benefit of the app mirrored the app's main user benefit - providing them with Mediatoolkit functionalities and experience on-the-go, all within the same ecosystem."
&lt;/h1&gt;

&lt;h5&gt;
  
  
  Filip Fajdetić
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Bornfight iOS Development Team Lead
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Defining app features based on users’ core needs
&lt;/h2&gt;

&lt;p&gt;By working closely with Mediatoolkit’s Customer Success team, we gathered a large amount of data about the behavior of their users and their needs. Detailed analysis of that data enabled us to create a list of functionalities we needed to implement, as well as to define the ways users should move through the application and interact with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CrpkVMDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/177c3wngwuluxkfjvecw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CrpkVMDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/177c3wngwuluxkfjvecw.jpg" alt="Alt Text" width="880" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing the experience
&lt;/h2&gt;

&lt;p&gt;Making sure that the mobile app compliments the experience of using Meditoolkit’s web tool was one of our key objectives. We achieved that by placing a strong emphasis on the overall visual identity that matches the one on the website, as well as by focusing on core actions and elements users interact with the most.&lt;/p&gt;

&lt;h1&gt;
  
  
  "As the application itself displays a large number of information to users, we maxed out on functionality - utilizing native components and giving a clear role to every visual element within the app."
&lt;/h1&gt;

&lt;h5&gt;
  
  
  Elena Crnković
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Digital Design Team Lead
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Allowing users to create their perfect flow
&lt;/h2&gt;

&lt;p&gt;The mobile application needed to compliment the Mediatoolkit web tool by adapting to different workflows of its users, so we enabled them to customize certain aspects of app itself – from core actions like setting up keywords and queries, all the way to defining how they’d like to receive notifications or times when the app shouldn’t disturb them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M9PBeRxW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6yplw2k66jkuveu9pg6b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M9PBeRxW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6yplw2k66jkuveu9pg6b.jpg" alt="Alt Text" width="880" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete focus on app fluidity and intuitiveness
&lt;/h2&gt;

&lt;p&gt;Mediatoolkit is an extremely powerful tool that offers its users a wide variety of features and options for tracking keywords and mentions. To make it simple and intuitive to use, especially on small mobile screens, we focused on designing a streamlined app architecture that seamlessly guides users through all of its functionalities – from the initial onboarding to real-time tracking.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iAGx8sVk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qmd2vwfrdeny1srx8h39.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iAGx8sVk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/qmd2vwfrdeny1srx8h39.jpg" alt="Alt Text" width="880" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  "Users need to get notified about new mentions as soon as possible - that is the most important aspect of the app and it needs to work flawlessly. Zero compromise."
&lt;/h1&gt;

&lt;h5&gt;
  
  
  Tomislav Smrečki
&lt;/h5&gt;

&lt;h6&gt;
  
  
  Bornfight Android Development Team Lead
&lt;/h6&gt;

&lt;h2&gt;
  
  
  Natively developed for both iOS and Android
&lt;/h2&gt;

&lt;p&gt;As iOS and Android have different UI patterns, we created a separate mobile app for each operating system. Functionalities and the overall experience Mediatoolkit’s users were accustomed to remained the same – they were just tailored to each of the platforms and their specific standards. This native development approach made the applications more fluid and increased their performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mobile application results
&lt;/h2&gt;

&lt;p&gt;After the launch of the new application for iOS and Android, Mediatoolkit experienced a surge in the number of mobile users.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;25% of Mediatoolkit’s monthly active users are using the new mobile application&lt;/li&gt;
&lt;li&gt;30% of all Mediatoolkit’s paid users have downloaded the new mobile application&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Download Mediatoolkit from the Google Play Store or the Apple App Store, and explore the benefits real-time media monitoring can bring your business!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NljEyx-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5y7q3ty91t2bmvbbkcgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NljEyx-C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/5y7q3ty91t2bmvbbkcgr.png" alt="Alt Text" width="880" height="497"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;We’re available for partnerships and open for new projects. If you have an idea you’d like to discuss, &lt;a href="https://www.bornfight.com/contact/"&gt;share it with our team &lt;/a&gt;!&lt;/p&gt;

</description>
      <category>dev</category>
      <category>casestudy</category>
      <category>mobileapp</category>
      <category>design</category>
    </item>
    <item>
      <title>Apple watchOS tutorial: creating a countdown app</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Fri, 22 May 2020 09:15:16 +0000</pubDate>
      <link>https://forem.com/bornfight/apple-watchos-tutorial-creating-a-countdown-app-566c</link>
      <guid>https://forem.com/bornfight/apple-watchos-tutorial-creating-a-countdown-app-566c</guid>
      <description>&lt;h2&gt;
  
  
  With the launch of the Apple Watch Series 5 comes a new watchOS 6 update which brings us a lot of new and exciting stuff.
&lt;/h2&gt;

&lt;p&gt;Some of the new features in this update include new watch faces, new health features and, for the first time, a dedicated App Store. You can download apps for your Apple Watch without an iPhone and that brings us to another major update – you can now develop apps exclusively for watchOS without the need to also create an iOS app.&lt;/p&gt;

&lt;p&gt;So, with all these new updates, I decided it’s time for me to try and build my own watchOS app, and use this opportunity to see the differences between developing iOS and watchOS apps.&lt;/p&gt;

&lt;p&gt;So let’s get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea behind the application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What will you be needing?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Xcode 11 (for building only watchOS apps)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s pretty much everything you’ll need since you don’t actually need an Apple Watch to create an Apple Watch app – Xcode has all the simulators you need. If you plan on developing both an iPhone and an Apple Watch app, it’s better to have an actual Apple Watch because the communication between Apple Watch and iPhone is a bit delayed, and when you’re using simulators you don’t get the actual feeling of the duration of this delay.&lt;/p&gt;

&lt;h3&gt;
  
  
  What will we actually be developing?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A simple countdown app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can have all your important events and dates in one place, and use the app as a reminder or a timer for each one. For example, you can add your vacation plans or maybe someone’s birthday.&lt;/p&gt;

&lt;p&gt;Our app is going to be a simple app with tableView on the first screen – with a list of all our important events, a single screen for each of those events and a few important pieces of information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s talk about the setup
&lt;/h2&gt;

&lt;p&gt;Now that we are ready and have all the information we need, we can start by creating a new project by opening Xcode and choosing to Create a new Xcode project → Watch App and click next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mtt5cVIh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body01.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mtt5cVIh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body01.jpg" alt="Image: bornfight_blog_milisa_appleos_body01" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next screen, give your new app a name and add a few more specifics for your app – like are you going to be using Storyboard or SwiftUI. In this case, we’ll be using Storyboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gxf-xaWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body02.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gxf-xaWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body02.jpg" alt="Image: bornfight_blog_milisa_appleos_body02" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After choosing everything you want to include/exclude from your app, click next.&lt;/p&gt;

&lt;p&gt;OK, you have created your Apple Watch project and, as you can see, the structure of your project consists of two parts: WatchKit App and WatchKit Extension. You need both of them to develop the watchOS app. The main difference between them is that the WatchKit App deals with displaying UI, so you need to store all your assets and storyboards (if you are using them) here. At the same time, everything that includes code is stored in WatchKit Extension, so all your controllers and other classes need to be stored here. Also, if you are using some images or other assets, you need to store them inside Extension as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GGHCtQOq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body03.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GGHCtQOq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body03.jpg" alt="Image: bornfight_blog_milisa_appleos_body03" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the app UI
&lt;/h2&gt;

&lt;p&gt;We are going to start by creating a user interface. The first step is selecting the interface storyboard – here you can see an empty interface controller, which is equivalent to the view controller in iOS apps. You can drag and drop elements in the same way you do in iOS apps, with the main difference being you can’t position elements using constraints or resize them, you can simply add another element beneath the previous element. If you want to add elements horizontally, you need to use groups that are most similar to stack views in iOS. You will see examples of this as we develop our app.&lt;/p&gt;

&lt;p&gt;To create our first screen with tableView, we’ll start by dragging a table from the Object Library onto our empty Interface controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LhiwIUkg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body04.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LhiwIUkg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body04.jpg" alt="Image: bornfight_blog_milisa_appleos_body04" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, the table row is actually a group, so you can just drag and drop other UI elements into it. We want to display our event’s title, date and image in each table row, and we’ll add a separator for decoration – but vertically, not horizontally. Since we want our table view row to be filled horizontally, we are going to use groups. Start by dragging a new group from the Object Library and set its layout to horizontal. Then add a separator and another group – only this one will be filled vertically since we want our two labels to be beneath one another. After doing so, your interface object hierarchy should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SijhJB8x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body05.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SijhJB8x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body05.jpg" alt="Image: bornfight_blog_milisa_appleos_body05" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And at the end, add an image view. The end result should look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k-y32zBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body06.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k-y32zBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body06.jpg" alt="Image: bornfight_blog_milisa_appleos_body06" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our table view screen is set and we can start creating our interface controller for a single event. Start by dragging another interface controller and setting its identifier as Event in the Attributes inspector, so you can refer to this interface controller in code. On this screen, you won’t be needing a group since all our elements are going to be beneath one another. You can just drag image view, two labels and a timer onto the controller. After setting the desired positions and colors, your controller should be similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V_Z4R4BR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body07.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V_Z4R4BR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body07.jpg" alt="Image: bornfight_blog_milisa_appleos_body07" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we are all set on the UI part, we can switch to the coding part of our app – that means we are switching to the WatchKit Extension group of our project.&lt;/p&gt;

&lt;h2&gt;
  
  
  The process of creating controllers
&lt;/h2&gt;

&lt;p&gt;For our app, we are going to use the existing InterfaceController with little modifications. We are going to start by deleting everything except the class definition. The next thing we need to do is connect our outlets in the storyboard to our controller, so we can access them from code. To do this, we need to go to our storyboard and select our first interface (the one with table view) and set its class to InterfaceController. Now that we connected our outlets, we can add our mock database that has a few Event objects. Every Event object consists of a name, a date and a category. The category determines the photo and the color of each event.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ry2rNfQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pgr2m297h0xg0hrqckx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ry2rNfQS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/pgr2m297h0xg0hrqckx3.png" alt="Alt Text" width="880" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we’re done with this part, we need to create a new controller – this time for each row of our interface table. Interface tables in WatchKit are much simpler than iOS tables – they don’t have delegates or data sources, and we only need a controller for each type of cell we use inside the table. Even though its name is a row controller, it is a subclass of NSObject. So, to create our EventRowController, we need to right-click on the WatchKit Extension group and choose the New file → WatchKit class and write its name, make sure we set the subclass to NSObject and click next and then create.&lt;/p&gt;

&lt;p&gt;Now, let’s go back to our storyboard, select our table row on our first interface controller and set its class to EventRowController. This enables us to connect UI elements to code. After doing so, add this part below the outlets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz6TyHWM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d0jjnmepi7eookzdg6mt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uz6TyHWM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d0jjnmepi7eookzdg6mt.png" alt="Alt Text" width="880" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With this, our EventRowController is set. Now we need to pass an instance of Event to each row of our table. We need to go back to our InterfaceController and add this part of the code below the outlets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iqWwYRWO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/woze9k498qjejvcs10jp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iqWwYRWO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/woze9k498qjejvcs10jp.png" alt="Alt Text" width="880" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After building and running our project, you’ll get something that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XESrmnPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body08.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XESrmnPd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_milisa_appleos_body08.jpg" alt="Image: bornfight_blog_milisa_appleos_body08" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we need to define what happens when the user selects a row. We need to add the following code to our InterfaceController:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DS_ft_lu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dhky4gssms6cthh7q29i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DS_ft_lu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dhky4gssms6cthh7q29i.png" alt="Alt Text" width="880" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our table is ready and now we need to create our single event controller. Right-click on the WatchKit extension and choose New File → WatchKit class. Add a new controller name, in our case EventInterfaceController and set its subclass of WKInterfaceController. When you’re done, click next and then create.&lt;/p&gt;

&lt;p&gt;Now we need to connect our storyboard interface again, so go to storyboard but this time to our second interface controller – set its class to EventInterfaceController. Now connect all of the UI elements to the code.&lt;br&gt;
Add this part of the code below the outlets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zkcVhP6S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4w4guaktt0qxt1s2tobm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zkcVhP6S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4w4guaktt0qxt1s2tobm.png" alt="Alt Text" width="880" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This last part of the code we added initializes our interface controller with the specified context data if there is any. In our case, the context object is Event and it has been provided by the previous interface controller.&lt;/p&gt;

&lt;p&gt;We’ll also need a method for setting our timer, so add this part of the code as well:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qxtuUzBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a91scelh7b1vc7m0bf0q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qxtuUzBl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/a91scelh7b1vc7m0bf0q.png" alt="Alt Text" width="880" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that our EventInterfaceController is ready, we can build and run the app. You should get something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KVqL_FJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/watch.gif%3Fx22406" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KVqL_FJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/watch.gif%3Fx22406" alt="Alt text of image" width="592" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this gives us our first watchOS app&lt;/p&gt;

&lt;h2&gt;
  
  
  What we learned by doing this
&lt;/h2&gt;

&lt;p&gt;To conclude this blog post, I have to say I expected that developing my first Apple Watch app will be more challenging than it actually was. I guess that was because I was doing something new that I haven’t done before and I didn’t really know what to expect.&lt;/p&gt;

&lt;p&gt;I also detected a couple of key differences between iOS and watchOS apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you use WatchKit instead of UIKit and that means you can’t use standard 
UI elements iOS developers got used to&lt;/li&gt;
&lt;li&gt;you have a lot less screen space so that means smaller number of UI 
elements&lt;/li&gt;
&lt;li&gt;you need to watch out for battery life – Apple Watch has a 
significantly smaller battery than an iPhone&lt;/li&gt;
&lt;li&gt;users spend very little time using watchOS apps
there is no keyboard, so use text input only if it’s absolutely 
necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you liked this basic tutorial for building your first Apple Watch app. You can use it as an inspiration for your own apps. Here is the  &lt;a href="https://github.com/tamaramilisa/WatchCountdown"&gt;github repo &lt;/a&gt;! if you want to check it out!&lt;/p&gt;




&lt;p&gt;We’re available for partnerships and open for new projects. If you have an idea you’d like to discuss, &lt;a href="https://www.bornfight.com/contact/"&gt;share it with our team &lt;/a&gt;!&lt;/p&gt;

</description>
      <category>applewatch</category>
      <category>ios</category>
      <category>app</category>
      <category>development</category>
    </item>
    <item>
      <title>Tips for creating an app monetization strategy</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Tue, 31 Mar 2020 13:00:53 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/tips-for-creating-an-app-monetization-strategy-3jh1</link>
      <guid>https://forem.com/bornfightcompany/tips-for-creating-an-app-monetization-strategy-3jh1</guid>
      <description>&lt;h2&gt;
  
  
  Mobile app development can be expensive. That is why you want to have as much control over as many elements that could affect your success on the market as you can.
&lt;/h2&gt;

&lt;p&gt;There are a multitude of reasons why defining a monetization strategy, doing user research, defining goals and choosing the right model for a mobile application before even starting any actual development on said application starts is a good idea - from the ability to create a more streamlined production roadmap for your app and structuring a detailed promotion plan, all the way to maximizing the chance of succeeding on the market by focusing on a specific approach.&lt;br&gt;
Now, we’ll assume that you’re reading this post because you’re planning on creating your own mobile application and don’t want some random element to decide if your application will succeed or fail, so we’ll give you a couple of tips for creating a mobile app monetization strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #01: consider the type of mobile app you want to create
&lt;/h3&gt;

&lt;p&gt;Some monetization models only work with specific types of applications, so you need to keep that in mind while you’re defining your strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #02: understand your target persona
&lt;/h3&gt;

&lt;p&gt;If you want your product to be successful on the market, you need to know who is it for, how those customers will use it, what will make them buy it and what do they want to get out of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #03: answers the question: ‘why would anyone buy my app’
&lt;/h3&gt;

&lt;p&gt;If your app is to be successful, it needs to provide users with something original, valuable or better than what the competition is currently offering - define that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #04: define what else would your users be willing to pay for
&lt;/h3&gt;

&lt;p&gt;To make the income you earn grow together with your application’s user base, you need to define specific elements within the app that could be monetized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #05: see what your competition is doing
&lt;/h3&gt;

&lt;p&gt;Explore their product, their business strategies, the way they do sales, how they speak to customers - try to define what they are doing good and what they are doing bad.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #06: provide value to your users
&lt;/h3&gt;

&lt;p&gt;A line between providing value while maximizing revenue and being named a cash grab is thin - make sure you’re always on the right side of that line because user trust is difficult to get back.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #07: define your goals with the app
&lt;/h3&gt;

&lt;p&gt;By defining specific goals you want to achieve with your mobile application, you’ll always have a guide that will keep you on the right track and help you make decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #08: be in it for the long run
&lt;/h3&gt;

&lt;p&gt;Establishing a relationship with users is a process that takes time, but users’ engagement with the application is directly connected to revenue, so it’s well worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #09: don’t sacrifice user experience
&lt;/h3&gt;

&lt;p&gt;When choosing the right monetization model, great user experience should be one of your top priorities - great user experience means users will be more likely to spend money.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #10: keep your eye on monetization trends
&lt;/h3&gt;

&lt;p&gt;Google and Apple are major players in the app space, and their action can have a big effect on the entire app ecosystem, so you should follow what they’re up to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #11: don’t try to reinvent the wheel
&lt;/h3&gt;

&lt;p&gt;The app market is filled with examples of apps successfully using various monetization models and strategies - use those insights to your advantage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tip #12: test, get feedback, iterate, repeat
&lt;/h3&gt;

&lt;p&gt;Just because you defined a monetization strategy that fits your app and your users, that doesn’t mean you’re done with it.&lt;br&gt;
Keep developing and upgrading it based on your users’ behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you want to find out more about mobile app monetization, most effective app monetization models and the future of monetization, click &lt;a href="https://www.bornfight.com/resources/business-models-for-mobile-app-monetization/?utm_source=dev.to&amp;amp;utm_medium=outbound&amp;amp;utm_campaign=ebook_b_2020&amp;amp;utm_term=MobileAppMonetization"&gt;here&lt;/a&gt; and download our full ebook for free. ##
&lt;/h2&gt;

</description>
      <category>mobileappmonetization</category>
      <category>monetization</category>
      <category>mobileappdev</category>
    </item>
    <item>
      <title>What is mobile app monetization?</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Fri, 27 Mar 2020 12:23:39 +0000</pubDate>
      <link>https://forem.com/bornfight/what-is-mobile-app-monetization-1c7o</link>
      <guid>https://forem.com/bornfight/what-is-mobile-app-monetization-1c7o</guid>
      <description>&lt;h2&gt;
  
  
  Understanding how to monetize your mobile application is a crucial aspect of app development, as it will help you earn revenue while you’re satisfying your users needs and providing them with a great user experience.
&lt;/h2&gt;

&lt;p&gt;Whether you’re running a large international enterprise with thousands of employees and clients, or you’re a solo developer looking to build your first app, you need to understand how to generate money from your mobile application in a way that would be most beneficial for your business, but also your users. &lt;/p&gt;

&lt;p&gt;So, what exactly is app monetization? The short answer would be the process of leveraging an application’s user base and converting their actions and engagement into a stream of revenue. A more detailed answer would be that monetization is a specific framework that defines the exact ways in which a mobile application drives revenue and generates return on investment (ROI) - a framework that enables you to answer these questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What source of income am I pursuing with the application?&lt;/li&gt;
&lt;li&gt;What value will I be providing and at what price?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mobile app monetization is a way for you to earn income from your mobile application - it enables you to take luck and chance out of the picture, and take control of the aspects that affect the success of your application on the market.&lt;/p&gt;

&lt;p&gt;In an ideal world, you could create a mobile application, launch it and immediately start earning money. Since the current app ecosystem isn’t an ideal world, you need a monetization strategy to take care of the money aspect.&lt;/p&gt;

&lt;h3&gt;
  
  
  If you want to find out more about mobile app monetization, most effective app monetization models and the future of monetization, click &lt;a href="https://www.bornfight.com/resources/business-models-for-mobile-app-monetization/?utm_source=dev.to&amp;amp;utm_medium=outbound&amp;amp;utm_campaign=ebook_b_2020&amp;amp;utm_term=MobileAppMonetization"&gt;here&lt;/a&gt; and download our full ebook for free.
&lt;/h3&gt;

</description>
    </item>
    <item>
      <title>Nuxt.js over Vue.js: when should you use it and why</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Tue, 10 Mar 2020 11:13:58 +0000</pubDate>
      <link>https://forem.com/bornfightcompany/nuxt-js-over-vue-js-when-should-you-use-it-and-why-ap6</link>
      <guid>https://forem.com/bornfightcompany/nuxt-js-over-vue-js-when-should-you-use-it-and-why-ap6</guid>
      <description>&lt;h2&gt;
  
  
  Nuxt.js is a frontend framework built upon Vue.js that offers great development features such as server side rendering, automatically generated routes, improved meta tags managing and SEO improvement.
&lt;/h2&gt;

&lt;p&gt;Our Front-end team didn’t really consider using Nuxt.js as a main technology on the client side until we recently received a request for a unique project with a number of very specific features. As this was also the first time a couple of members in our team used Nuxt.js, I decided to write this blog to explain how it worked for us.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why would you use Nuxt.js over Vue?
&lt;/h3&gt;

&lt;p&gt;Nuxt.js offers many benefits to front-end developers, but there was one key feature that made our decision to use this framework final – SEO improvement. Our application needs this feature because it is not a typical internal SPA (single-page application). It’s a public web application that includes social sharing features and management.&lt;/p&gt;

&lt;p&gt;Speaking of social sharing, Nuxt.js has great meta tags managing, so we could easily make specific and customisable social share windows depending on the data received from back-end. Here’s one of the examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z9HtG2Z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body01.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z9HtG2Z5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body01.jpg" alt="Social Sharing Nuxt.js" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, how does SEO improvement work?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To improve SEO, Nuxt.js uses SSR (Server Side Rendering). SSR is fetching AJAX data and rendering Vue.js components into HTML strings on the server (Node.js). It sends them directly to the browser when all asynchronous logic is done, and then finally serves the static markup into a fully interactive app on the client. This feature allows for great parsing through DOM elements with the Google SEO parser. SEO parser is parsing through DOM elements with enormous speed immediately when the website DOM is loaded.&lt;/p&gt;

&lt;p&gt;On the other hand, typical SPA applications built with frameworks like Vue.js, React, Angular and similar are fetching data from backend with AJAX after DOM is loaded, and therefore SEO parser is not able to parse all of the DOM elements, because there are not yet rendered. AJAX fetching is asynchronous, while SEO parsing is not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sfgBWua6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body02.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sfgBWua6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body02.jpg" alt="Image: Nuxt.js SEO audit grade" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qYp4Jwuy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body03.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qYp4Jwuy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body03.jpg" alt="Image: Vue.js SEO audit grade" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt.js needs a different mindset that Vue
&lt;/h3&gt;

&lt;p&gt;Nuxt.js and Vue.js handle logic very differently. The main difference is that Vue is always running on the client side, while Nuxt is not, and that can cause major problems in some cases. For example – if you want to select a DOM element right after the application is loaded, there is a possibility that the app is running on the Node.js side, and of course, there are no DOM elements in Node.js.&lt;/p&gt;

&lt;p&gt;The same would happen when accessing a browser’s local storage. That is the main reason why Nuxt is using cookies over local storage – because they are always accessible.&lt;/p&gt;

&lt;p&gt;With Vue, we don’t have those kinds of problems because it is always running on the client, and therefore we do not have to bother with those kind of potential problems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s see how to handle this types of potential problems in Vue and how to do it in Nuxt – with actual code examples.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m6jAQiNV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body04.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m6jAQiNV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body04.jpg" alt="Image: Nuxt.js server/client handling" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most important thing in this picture is the early return in the “created” method. Nuxt has a globally accessible object “process” that shows us are we currently running on the server side or the client side. The logic behind the code we see is focused on managing socket connection, and obviously we do not want to update the DOM on receiving socket events if we are running on server, because there is no DOM on the server side. If this was a Vue.js application, the code would be identical, except for the early return part – because the process would always be running on client and there would never be a need to check that particular statement.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OQAVSWHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body05.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OQAVSWHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body05.jpg" alt="Image: Nuxt.js generated router based on folder structure" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuxt.js generates its own router based on the folder structure, while with Vue.js, it must be done manually – but keep in mind that there are pros and cons to both principles. Automatically generated router’s pros are that it is easier and faster to create one. You just create the directory and files, and Nuxt does all of the work. But the cons are that it is less controllable and manageable than a manually written one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p7p6b3uv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body06.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p7p6b3uv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body06.jpg" alt="Image: Vue.js manual router" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Vue.js you can easily add your own logic to the router, import services and have more control managing routes than with a manually generated router. This principle is more time consuming and more complex, but that doesn’t always mean it is worse because of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Nuxt ready for enterprise-scale applications?
&lt;/h3&gt;

&lt;p&gt;There used to be two main factors that made Nuxt.js unready for enterprise-scale applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Poor typescript support&lt;/li&gt;
&lt;li&gt;Bad server-side error handling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;While we were in the research phase of our project (some 6 months ago), there were no reliable Typescript start-kits or configurations whose usage was worth the risk. There were plenty of linting errors and missing types, so we decided to go with vanilla JS (ES6+). In the meantime, Typescript support for Nuxt.js has drastically improved and now there are new start-kits and configurations ready to be used without worrying about Typescript-related issues.&lt;/p&gt;

&lt;p&gt;Bad server-side error handling was the biggest and the most demanding issue we had to deal with while developing a Nuxt.js application. While code was executing on the Nuxt.js server (Node.js) side, the application was throwing very unrelated error messages, and it was really hard and complex to debug and fix those same errors. It was necessary to handle errors on the Node.js side in a specific way in order to make debugging simpler.&lt;/p&gt;

&lt;p&gt;Now, with better Typescript support and a deeper understanding of SSR, I can reliably say that Nuxt.js is ready for mid-scale and enterprise-scale applications, but there is still room for improvement – like better error handling and AJAX managing on the Node.js side of Nuxt.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nuxt application structure
&lt;/h3&gt;

&lt;p&gt;Nuxt.js has a very similar architecture to Vue.js. There are only two major differences:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Router&lt;/li&gt;
&lt;li&gt;Main App.vue component&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nuxt generates router logic and its routes based on the directory and file structure for pages. For example, if we create a directory and file &lt;strong&gt;“about/index.vue”&lt;/strong&gt;, Nuxt.js automatically creates the route &lt;strong&gt;“/about”&lt;/strong&gt; for that page. There is no need to define or configure routes anywhere else in application.&lt;/p&gt;

&lt;p&gt;For nested routes, creating a directory inside the parent directory is all that is necessary – &lt;strong&gt;“about/me/index.vue”&lt;/strong&gt; will generate the &lt;strong&gt;“about/me”&lt;/strong&gt; route. And for creating dynamic nested routes or nested route parameters, all that is required is to name the subdirectory with the lodash prefix – &lt;strong&gt;“user/_id/index.vue”&lt;/strong&gt; will create a dynamic nested route for users based on their id.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bWfxWcI3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body07.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bWfxWcI3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body07.jpg" alt="Image: Nuxt.js pages directory structure" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nuxt.js has one more structure-related feature that is very interesting – layouts. Vue.js applications have the main App.vue file, which is the main root component wrapper for all application components. Nuxt.js uses layouts, where every layout serves as an individual wrapper for application components. For example, if we want some specific pages to use different UI libraries, global CSS styles, font families, design systems, meta tags or other elements, we can define what layout to use as its parent root component. By default, all Nuxt.js pages are using the default.vue layout.&lt;/p&gt;

&lt;p&gt;Vuex in Nuxt.js is structured almost identically to the usual Vue.js environment – with store modules. This type of structuring is optional, but highly recommended for better structure and code maintenance. Every store should be structured and modularized based on the application logic and data flow. For instance, if the application contains authorization logic, we must create the authorization store module for managing all authorization data and logic, such as log in, log out, cookies, tokens, user data, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---oFDMBgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body08.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---oFDMBgn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body08.jpg" alt="Image: Nuxt.js store modules structure" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gqXHwFT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body09.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gqXHwFT3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/10/bornfight_blog_svjetlicic_nuxt_body09.jpg" alt="Image: Nuxt.js root application structure" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Developing your first Nuxt.js project will surely be confusing and complex at first, especially if you have Vue.js background without SSR knowledge. But just like any other technology, it takes time, mistakes and a lot of lines of code to truly understand the power and the benefits of the Nuxt.js framework. As for me, I’m eagerly awaiting my next Nuxt.js project where I’ll get to use my acquired knowledge (and hopefully Typescript) without encountering any obstacles from the previous Nuxt.js + Typescript project I worked on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you’re interested in learning more about Nuxt.js, I highly recommend you check out these sources:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.udemy.com/course/nuxtjs-vuejs-on-steroids/"&gt;Udemy course: Nuxt.js – Vue.js on Steroids&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/what-exactly-is-client-side-rendering-and-hows-it-different-from-server-side-rendering-bd5c786b340d/"&gt;freeCodeCamp article: Client-side vs. server-side rendering &lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nuxt.js is a very powerful framework with many useful features that make developing front-end applications easier and more entertaining. But keep in mind that it is not the best choice for all types of client-side applications and websites.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, to answer the main question – Nuxt.js or Vue.js? The answer is that you have to know the strengths and weaknesses of each, and you also need to know when to use one over the other based on the project type, goals and requirements.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nuxt offers better SEO improvement with its server-side rendering feature, faster development with auto-generic router, public share features and management with great configuration options and meta tags methods, automatic code splitting with pre-rendered pages – all of this is impossible or extremely complex to achieve with Vue.js. If these features are required for your next project, I assure you that Nuxt.js will be an excellent choice.&lt;/p&gt;

&lt;p&gt;On the other hand, if your goals are internal product, expanded code managing and coverage, typical client-side SPA, no need for SEO rate and performance, and manual code logic over generic solutions, then the obvious choice is Vue.js, as it’s far superior to Nuxt.js when it comes to handling all that.&lt;/p&gt;




&lt;p&gt;We’re available for partnerships and open for new projects. If you have an idea you’d like to discuss, &lt;a href="https://www.bornfight.com/contact/"&gt;share it with our team &lt;/a&gt;!&lt;/p&gt;

</description>
      <category>nuxt</category>
      <category>vue</category>
      <category>frontend</category>
      <category>framework</category>
    </item>
    <item>
      <title>Free e-book: Why businesses need product discovery workshops</title>
      <dc:creator>Bornfight</dc:creator>
      <pubDate>Tue, 28 Jan 2020 09:56:27 +0000</pubDate>
      <link>https://forem.com/bornfight/free-e-book-why-businesses-need-product-discovery-workshops-4o54</link>
      <guid>https://forem.com/bornfight/free-e-book-why-businesses-need-product-discovery-workshops-4o54</guid>
      <description>&lt;h2&gt;
  
  
  When it comes to building and launching a new product, the process can be extremely complex and require a lot of planning.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gka46X9r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/12/bornfight_blog_ebook_product_discovery_workshop_facebook-scaled.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gka46X9r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.bornfight.com/wp-content/uploads/2019/12/bornfight_blog_ebook_product_discovery_workshop_facebook-scaled.jpg" alt="Discovery Workshop Ebook Front Page" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As it is crucial to plan the initial project setup the right way, we wrote an e-book to help guide businesses through the whole planning process.&lt;/p&gt;

&lt;p&gt;This e-book is a quick start guide to understanding product discovery workshops that will help your business launch better software, applications and digital solutions.&lt;/p&gt;

&lt;p&gt;Its main focus is explaining the ins and outs of product discovery workshops and presenting their structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can you learn from this e-book?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What is product discovery&lt;/li&gt;
&lt;li&gt;Key benefits of product discovery for businesses&lt;/li&gt;
&lt;li&gt;How are product discovery workshops structured&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To become an owner of the full e-book, &lt;a href="https://www.bornfight.com/resources/why-businesses-need-product-discovery-workshops/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=ebook_b_2020&amp;amp;utm_term=ProductDiscoveryWorkshop"&gt;VISIT OUR WEBSITE&lt;/a&gt; and download for free.&lt;/p&gt;

</description>
      <category>books</category>
      <category>startup</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
