<?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: Fora Soft</title>
    <description>The latest articles on Forem by Fora Soft (@forasoft).</description>
    <link>https://forem.com/forasoft</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%2F709771%2F181dd31a-5a93-48c4-a104-b0bc61a964cd.png</url>
      <title>Forem: Fora Soft</title>
      <link>https://forem.com/forasoft</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/forasoft"/>
    <language>en</language>
    <item>
      <title>Picture-in-Picture Mode On iOS: Implementation and Peculiarities</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Thu, 25 May 2023 14:37:42 +0000</pubDate>
      <link>https://forem.com/forasoft/picture-in-picture-mode-on-ios-implementation-and-peculiarities-mog</link>
      <guid>https://forem.com/forasoft/picture-in-picture-mode-on-ios-implementation-and-peculiarities-mog</guid>
      <description>&lt;p&gt;The Picture-in-Picture (PiP) mode allows users to watch videos in a floating window on top of other windows. They can move it around the screen and place in any convenient spot. This feature enables users to keep an eye on what they are watching while interacting with other websites or applications.&lt;/p&gt;

&lt;p&gt;We have previously covered the &lt;a href="https://forasoft.com/blog/article/picture-in-picture-on-android-tutorial-527"&gt;PiP implementation on Android&lt;/a&gt; with code examples. In this article, we will focus on iOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picture in Picture is a must-have feature for modern multimedia applications
&lt;/h2&gt;

&lt;p&gt;Here’s why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Enhances multitasking.&lt;/strong&gt; PiP allows users to simultaneously watch videos or view images in a small window while maintaining access to the main content or application interface. This enables users to multitask, e.g. watch a video while checking emails, sending messages, or browsing social media.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Improves user experience.&lt;/strong&gt; The mode provides more flexible and convenient app navigation. This significantly enhances the user experience by eliminating the need to interrupt content playback or switch contexts completely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Minimizes session interruptions.&lt;/strong&gt; PiP enables users to continue watching or tracking content while performing other tasks. This helps reduce interruptions and ensures a smoother and uninterrupted workflow. For example, a user can watch a tutorial or a YouTube livestream while searching for information on the Internet or taking notes.&lt;/p&gt;

&lt;p&gt;All these factors help retain users within the application and increase the duration of app usage sessions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Peculiarities and difficulties of PiP on iOS
&lt;/h2&gt;

&lt;p&gt;Apple envisages two scenarios for using PiP on iOS:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;For video content playback&lt;/li&gt;
&lt;li&gt;For video calls&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The main issue is that for the video call scenario, prior to iOS 16 and for iPads that do not support Stage Manager, it is necessary to request special permission from Apple to access the camera in multitasking mode (com.apple.developer.avfoundation.multitasking-camera-access). But even after waiting for several months, as in our case, Apple may still not grant these permissions.&lt;/p&gt;

&lt;p&gt;Therefore, in our mobile video chat app, &lt;a href="https://apps.apple.com/en/app/fora-soft-video-calls/id1584317338"&gt;Tunnel Video Calls&lt;/a&gt;, we decided not to use such a scenario. Instead, we adopted the approach where a video call and its content are considered as video playback.&lt;/p&gt;

&lt;h2&gt;
  
  
  PiP lifecycle on iOS
&lt;/h2&gt;

&lt;p&gt;The Picture-in-Picture mode is essentially the content exchange between a full-screen app and PiP content from another app. The lifecycle of this exchange can be schematically represented as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nl0JwvUj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b466l2lsx1c5tza0uaec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nl0JwvUj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b466l2lsx1c5tza0uaec.png" alt="Stages of transitioning to the PiP mode on iOS" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Video is playing in full-screen mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user initiates an event that triggers the transition to PiP mode, such as pressing a specific button or minimizing the app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An animation is launched to transition the video to PiP mode — the full-screen video shrinks into a thumbnail and moves to the corner of the screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The transition process completes, and the application changes its state to the background state.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then, when it is necessary to bring the video back to full-screen mode from PiP mode, the following steps occur:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The app is in the background state and displays PiP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An event occurs that initiates the transition from PiP to full-screen mode and stops the Picture in Picture mode – such as pressing a button or expanding the app. The app enters the foreground.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An animation is launched to transition the video to full-screen mode. The app enters the state of displaying the video in full-screen.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1r87TdVu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bvs8fw6cv7t3bns9jld.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1r87TdVu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7bvs8fw6cv7t3bns9jld.png" alt="Steps to exit Picture in Picture mode on iOS" width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing PiP for video playback
&lt;/h2&gt;

&lt;p&gt;To enable PiP, you need to create an AVPictureInPictureController(playerLayer: AVPlayerLayer) object, and it must have a strong reference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if AVPictureInPictureController.isPictureInPictureSupported() { 
    // Create a new controller, passing 

 the reference to the AVPlayerLayer. 
    pipController = AVPictureInPictureController(playerLayer: playerLayer) 
    pipController.delegate = self 
    pipController.canStartPictureInPictureAutomaticallyFromInline = true 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to start playing the video content.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func publishNowPlayingMetadata() { 
    nowPlayingSession.nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo 
    nowPlayingSession.becomeActiveIfPossible() 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, when the button is pressed or the app is minimized/expanded, the PiP will activate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func togglePictureInPictureMode(_ sender: UIButton) { 
    if pipController.isPictureInPictureActive { 
        pipController.stopPictureInPicture() 
    } else { 
        pipController.startPictureInPicture() 
    } 
} 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementing PiP for video calls&lt;/p&gt;

&lt;p&gt;Implementing Picture in Picture mode in an iOS app for video calls using WebRTC technology is perhaps the most challenging part of the work. We would be happy to help you with it, so please &lt;a href="https://forasoft.com/contacts"&gt;reach out to us&lt;/a&gt; to discuss the details. Conceptually:&lt;/p&gt;

&lt;p&gt;In this implementation, the camera will not capture the user’s image, and you will only be able to see the conversation partner.&lt;/p&gt;

&lt;p&gt;To achieve this, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create an AVPictureInPictureController object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Obtain the RTCVideoFrame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Retrieve and populate CMSampleBuffer based on RTCVideoFrame.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pass the CMSampleBuffer and display it using AVSampleBufferDisplayLayer.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here’s a sequence diagram illustrating the process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wWJ6EPn---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffbx2i7zawl942vflv9x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wWJ6EPn---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ffbx2i7zawl942vflv9x.png" alt="PiP on iOS sequence diagram" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ios</category>
      <category>mobile</category>
      <category>pip</category>
      <category>webrtc</category>
    </item>
    <item>
      <title>How To Implement Screen Sharing To Your Android App [2023]. With Code Examples</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Tue, 18 Apr 2023 14:32:06 +0000</pubDate>
      <link>https://forem.com/forasoft/how-to-implement-screen-sharing-to-your-android-app-2023-with-code-examples-2ogc</link>
      <guid>https://forem.com/forasoft/how-to-implement-screen-sharing-to-your-android-app-2023-with-code-examples-2ogc</guid>
      <description>&lt;p&gt;Screen sharing is almost the basic function of video call platforms. Skype, WhatsApp, Telegram, Teams, Google Meet. All these systems have this feature. &lt;/p&gt;

&lt;p&gt;We have already explained &lt;a href="https://forasoft.com/blog/article/how-to-implement-screen-sharing-in-ios-1193"&gt;how to implement screen sharing into a mobile iOS application&lt;/a&gt;. In this article we will explain how to do it on Android. With code examples. &lt;/p&gt;

&lt;p&gt;Also in other articles within our Android series you will learn &lt;a href="https://forasoft.com/blog/article/how-to-make-a-custom-android-call-notification-455"&gt;how to make custom call notification&lt;/a&gt; and &lt;a href="https://forasoft.com/blog/article/webrtc-development-services-432"&gt;how we develop WebRTC systems&lt;/a&gt; in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screen sharing implementation
&lt;/h2&gt;

&lt;p&gt;You can enable screen sharing immediately when you create a new video call, in advance, before it actually starts.&lt;/p&gt;

&lt;p&gt;However, we will take a glance at the most common case, when screen sharing starts after the call itself started.&lt;/p&gt;

&lt;p&gt;To simplify the description of the screen sharing implementation, let’s say that we already have a ready-made application with WebRTC calls. Read more about the &lt;a href="https://forasoft.com/blog/article/what-is-webrtc-156"&gt;implementation of the WebRTC video call&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Steps for implementation will be the following:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accessing screen content&lt;/li&gt;
&lt;li&gt;Creating a video track with a screen image&lt;/li&gt;
&lt;li&gt;Replacing the camera video track to the the screen video track&lt;/li&gt;
&lt;li&gt;Displaying a notification of an ongoing screen sharing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now each one in detail: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessing screen content&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First we get access to capturing the screen content and device sound with &lt;a href="https://developer.android.com/guide/topics/large-screens/media-projection"&gt;Media Projection API&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val screenSharingPermissionLauncher = registerForActivityResult( 
   ActivityResultContracts.StartActivityForResult() 
) { result -&amp;gt; 
   // Handle request result 
   val screenSharingIntent = result.data 
   if (screenSharingIntent != null) { 
       // Success request 
   } 
} 

val mediaProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager 
val intent = mediaProjectionManager.createScreenCaptureIntent() 
screenSharingPermissionLauncher.launch(intent)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When calling for screenSharingPermissionLauncher.launch(intent), a dialog window will appear. It will tell the user that media projection will access all the information displayed on the screen.&lt;/p&gt;

&lt;p&gt;As a result of successful access to the screen content we get screenSharingIntent&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a video track with a screen image&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create videoCapturer, which will capture the image from the screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val mediaProjectionCallback = object : MediaProjection.Callback() { 
   override fun onStop() { 
       // screen capture stopped 
   } 
} 
val videoCapturer = ScreenCapturerAndroid(screenSharingIntent, mediaProjectionCallback)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create localVideoTrack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", eglBase.eglBaseContext) 
val videoSource = peerConnectionFactory.createVideoSource(/* isScreencast = */ true) 
videoCapturer.initialize(surfaceTextureHelper,context, videoSource.capturerObserver) 
videoCapturer.startCapture(displayWidth, displayHeight, fps) 
val localVideoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Replacing the camera video track to the the screen video track&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To replace the video track correctly, implement the renegotiation logic for both call participants. When changing local media tracks, WebRTC calls onRenegotiationNeeded. It repeats the sdp exchange process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val peerConnectionObserver = object : PeerConnection.Observer { 
   ... 
   override fun onRenegotiationNeeded() { 
       // Launch sdp exchange 
       peerConnection.createOffer(...) 
   } 
} 
val peerConnection = peerConnectionFactory.createPeerConnection(iceServers, peerConnectionObserver) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to the video track replacing. Delete the camera video track from the local media:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localMediaStream.removeTrack(cameraVideoTrack) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stop capturing the camera video:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cameraVideoCapturer.stopCapture() 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add screen sharing video track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localMediaStream.addTrack(screenVideoTrack) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Displaying a notification about an ongoing screenshot&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the start of the screen sharing, it’s necessary to run the &lt;a href="https://forasoft.com/blog/article/foreground-service-and-deep-links-on-android-601"&gt;Foreground Service&lt;/a&gt; with the notification that the demonstration has started.&lt;/p&gt;

&lt;p&gt;Create a ScreencastService and add it to AndroidManifest.xml. Also specify the foregroundServiceType parameter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;service 
   android:name=".ScreencastService" 
   android:foregroundServiceType="mediaProjection" 
   android:stopWithTask="true" /&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before replacing the video trach from the camera with the screen sharing video track, launch ScreencastService:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val intent = Intent(this, ScreencastService::class.java) 
ContextCompat.startForegroundService(this, intent) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in ScreencastService (e.g. in onStartCommand()), call the startForeground method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;startForeground(NOTIFICATION_ID, notification) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common issues with implementation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The app crashes on Android 10+ devices with the “Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION” error&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Foreground Service ensures that the system will not “kill” the app during screen sharing. The Foreground Service notification will inform the user about the running screen sharing and will allow to quickly return to the application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to solve:&lt;/strong&gt; do not forget to display the notification about the started screen sharing 🙂 &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There is no replacement for the camera video track to the screen one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This might occur if the recognition logic is not implement (correctly) on one or both callers sides.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to solve:&lt;/strong&gt; override onRenegotiationNeeded method in PeerConnection.Observer (method name on other platforms may differ). When calling onRenegotiationNeeded, the sdp exchange process must be started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article we covered the implementation of screen sharing in video call and how you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access screen content with MediaProjection API&lt;/li&gt;
&lt;li&gt;Capture screen content with ScreenCapturerAndroid&lt;/li&gt;
&lt;li&gt;Create a local video track with screen image&lt;/li&gt;
&lt;li&gt;Replace the camera video track with the screen video track&lt;/li&gt;
&lt;li&gt;Implement Foreground Service for displaying screenshot notification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the final result of screen sharing implementation in &lt;a href="https://play.google.com/store/apps/details?id=com.forasoft.videocalls"&gt;our secure video calling app&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>mobile</category>
      <category>webrtc</category>
    </item>
    <item>
      <title>How to Teach Your iOS App Recognize Tone of Voice</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Mon, 10 Apr 2023 19:38:27 +0000</pubDate>
      <link>https://forem.com/forasoft/how-to-teach-your-ios-app-recognize-tone-of-voice-13ad</link>
      <guid>https://forem.com/forasoft/how-to-teach-your-ios-app-recognize-tone-of-voice-13ad</guid>
      <description>&lt;p&gt;Learn more about neural networks and how they work in general in one of &lt;a href="https://forasoft.com/blog/article/neural-networks-on-android-369"&gt;our previous materials with comics&lt;/a&gt;. This article is a guide to how to work with them on iOS. And in particular, how to implement speech recognition and characterize what's recognized. With code examples.&lt;/p&gt;

&lt;p&gt;We will explain it with an example /solution that we have developed for one of &lt;a href="https://forasoft.com/projects"&gt;our projects&lt;/a&gt;. Starting with quick intro into the framework we will be using, we'll then proceed to creating a model, training it with your app data, and analyzing results.&lt;/p&gt;

&lt;h2&gt;
  
  
  What framework to use: about CoreML
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/coreml"&gt;CML (Core Machine Learning)&lt;/a&gt; - is an Apple framework for implementing machine learning to an iOS app. Apple built it in 2016 as a supplement to what they had on working with matrixes and vector algebra (together building up the Accelerate framework) and computing based on the &lt;a href="https://developer.apple.com/documentation/metalperformanceshaders"&gt;Metal&lt;/a&gt; graphic technology - core neural network tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ntOroI3o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3oxm9v9iwaw8u0yte0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ntOroI3o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3oxm9v9iwaw8u0yte0t.png" alt="Neural network frameworks hierarchy: top level uses the results from the bottom layers" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CoreML has nothing to do with neural network training. It is only able to import a ready-made, trained model and provide the developer with a user-friendly interface to work with it in the application. For example, we submit the text to the input of the ML model and get its classification at the output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3kvptSe5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3widp2ne9lt8u16emuie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3kvptSe5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3widp2ne9lt8u16emuie.png" alt="Simplified text classifier scheme" width="800" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For that CoreML integrates a fully trained model, it provides a powerful flexible tool for working with neural networks. It is possible to import almost all popular neural networks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BERT, GPT - for tasks with natural language, the one we speak every day, &lt;/li&gt;
&lt;li&gt;neural networks for image classification, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's just one limitation: the number of tensor components must be &amp;lt;= 5. That is, no more than 5 dimensions.&lt;/p&gt;

&lt;p&gt;We should mention what a neural network model is. This is the result of neural network training that contains a weighted graph with the best combination of weights. And gives out a result at the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to determine the phrase toxicity on iOS in real-time?
&lt;/h2&gt;

&lt;p&gt;You can apply the algorithm below to characterizing speech in general. But to exemplify, we'll focus on the toxicity.&lt;/p&gt;

&lt;p&gt;So, to determine the toxicity of a phrase, you need to divide the problem into several phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prepare training data with toxic and non-toxic phrases;&lt;/li&gt;
&lt;li&gt;Obtain a model of the neural network trained on the data set;&lt;/li&gt;
&lt;li&gt;Write down the phrase;&lt;/li&gt;
&lt;li&gt;Send the phrase to the SFSpeechRecognition library for voice analysis and get the phrase in text;&lt;/li&gt;
&lt;li&gt;Send the text of the trained model to the classification and get the result.
To describe it with a diagram, the problem is as follows:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WoME9hny--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtn0vr6521yhgnaj0prk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WoME9hny--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtn0vr6521yhgnaj0prk.png" alt="Speech recognition model scheme" width="800" height="497"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now each phase in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 1: preparing the data for the speech classification model training
&lt;/h3&gt;

&lt;p&gt;To get a trained model you can go two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Develop the neural network yourself and train the model;&lt;/li&gt;
&lt;li&gt;Take a ready-made model and ready-made neural network, train it on your own data set, use &lt;a href="https://www.python.org/"&gt;Python&lt;/a&gt; as a tool, for instance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To simplify the process, we'll go the second way. Apple has an excellent set of tools for this, so starting with Xcode 13, the debugging process of the model became as simple as possible.&lt;/p&gt;

&lt;p&gt;To begin with, launch the CreateML tool (it's already in XCode) and create a new project. Select TextClassification (Apple uses BERT) and create a project. You'll see a window for uploading the prepared data.&lt;/p&gt;

&lt;p&gt;On the output, the tool accepts two datasets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the set for the model to complete its learning;&lt;/li&gt;
&lt;li&gt;the set to compare the results to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the data must be in json or csv. The dataset structure should follow the template:&lt;/p&gt;

&lt;p&gt;For json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ 
   { 
       "text": "The movie was fantastic!", 
       "label": "positive" 
   }, { 
       "text": "Very boring. Fell asleep.", 
       "label": "negative" 
   }, { 
       "text": "It was just OK.", 
       "label": "neutral" 
   } ... 
] 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For csv:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;text,label 
"The movie was fantastic!",positive 
"Very boring. Fell asleep.",negative 
"It was just OK.",neutral 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The data is ready, now you can upload and start training the model:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KtmscHz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lasgzndr84f9mkbbdkur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KtmscHz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lasgzndr84f9mkbbdkur.png" alt="Starting a new training" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to tell everything is ready and works correctly?&lt;/strong&gt;&lt;br&gt;
To evaluate the results, there are reports for each learning project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LdqdbE21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96rrgr2aia7m96ydg0xe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LdqdbE21--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/96rrgr2aia7m96ydg0xe.png" alt="Training results report" width="800" height="149"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precision&lt;/strong&gt; - how well the model identifies the target (in our case the target is the phrase to characterize), with with no false-alarm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recall&lt;/strong&gt; - how correctly the model identifies the target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;F1 score&lt;/strong&gt; - an indicator that combines the accuracy and complexity of the algorithm. Here's how you calculate it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iiV-y9xA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivvmnq0rcav3fst3m7be.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iiV-y9xA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ivvmnq0rcav3fst3m7be.png" alt="F1 score formula" width="530" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The higher the Precision and Recall, the better. However, in reality, it is impossible to reach the maximum of both indicators at the same time.&lt;/p&gt;

&lt;p&gt;All you have left to do is to export the received model, in *.mlmodel.&lt;/p&gt;
&lt;h3&gt;
  
  
  Phase 2: receiving the audio signal and sending it for speech recognition
&lt;/h3&gt;

&lt;p&gt;On iOS it is the Speech framework translates voice into text. There's a trained model in it already. Since our main task is to translate speech to text in real time, the first thing to do is to get the samples of the AVAudioPCMBuffer audio signal and them to the recognizer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AudioRecordService { 
   private var audioEngine: AVAudioEngine? 
   func start() { 
            do { 
                audioEngine = try configureAudioEngine() 
            } catch { 
                audioRecordingEvents.onNext(.error(.startingAudioEngineError)) 
            } 
    } 
    private func configureAudioEngine() throws -&amp;gt; AVAudioEngine { 
        let audioEngine = AVAudioEngine() 
        let inputNode = audioEngine.inputNode 
        let recordingFormat = inputNode.outputFormat(forBus: 0) 
        inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] buffer, _ in 
            self?.audioRecordingEvents.onNext(.audioBuffer(buffer)) 
        } 
        audioEngine.prepare() 
        try audioEngine.start() 
        return audioEngine 
    } 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set a zero-bus branch and the samples will arrive as soon as the audio frame number is 1024. By the way, a AVAudioNode object can potentially have several input and output buses.&lt;/p&gt;

&lt;p&gt;Send the received buffer for speech recognition:&lt;/p&gt;

&lt;p&gt;Create an enumeration for error processing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum SpeechReconitionError { 
    case nativeError(String) 
    case creatingTaskError 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create an enumeration for recognition events&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum SpeechReconitionEvents { 
    case phrase(result: String, isFinal: Bool) 
    case error(SpeechReconitionError) 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a SFSpeechRecognizer object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private var request: SFSpeechAudioBufferRecognitionRequest? 
private var reconitionTask: SFSpeechRecognitionTask? 
private let recognizer: SFSpeechRecognizer? 
 init() { 
        recognizer = SFSpeechRecognizer(locale: Locale.preferredLanguages[0]) 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure recognizer and launch the recognition task&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func configureRecognition() { 
        request = SFSpeechAudioBufferRecognitionRequest() 
        if #available(iOS 16.0, *) { 
            request?.addsPunctuation = true 
        } 
       if let supports = recognizer?.supportsOnDeviceRecognition, supports { 
            request?.requiresOnDeviceRecognition = true 
        } 
        request?.shouldReportPartialResults = true 
        guard let request else { 
            stopRecognition() 
            events.onNext(.error(.creatingTaskError)) 
            return 
        } 
  reconitionTask = recognizer?.recognitionTask(with: request, resultHandler: recognitionTaskHandler(result:error:)) 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The function to add audio buffers to the recognition queue&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func transcribeFromBuffer(buffer: AVAudioPCMBuffer) { 
        request?.append(buffer) 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the results processor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;private func recognitionTaskHandler(result: SFSpeechRecognitionResult?, error: Error?) { 
        if let result = result { 
            events.onNext(.phrase(result: result.bestTranscription.formattedString, isFinal: result.isFinal)) 
            if result.isFinal { 
                eraseRecognition() 
            } 
        } 

        if let error { 
            events.onNext(.error(.nativeError(error.localizedDescription))) 
            return 
        } 
    } 

    private func eraseRecognition() { 
        reconitionTask?.cancel() 
        request = nil 
        reconitionTask = nil 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The recognition process will start immediately after configureRecognition(). Then transfer the resulting audio buffers to transcribeFromBuffer(buffer: AVAudioPCMBuffer).&lt;/p&gt;

&lt;p&gt;The recognition process takes about 0.5–1 seconds. Therefore the result comes asynchronously in the function ecognitionTaskHandler(result: SFSpeechRecognitionResult?, error: Error?). SFSpeechRecognitionResult and contains the results of recognition of the last audio buffer, as well as the results of all previous recognitions. That is, on the screen the user sees the last recognized sentence and everything that was recognized earlier.&lt;/p&gt;

&lt;p&gt;Also, recognition doesn't always occur directly on the device. When offline recognition is not available, AVAudioPCMBuffer samples are sent to and processed on Apple servers. To verify and enforce the offline mode, use the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if let supports = recognizer?.supportsOnDeviceRecognition, supports { 
            request?.requiresOnDeviceRecognition = true 
 } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apple claims the on-device results are worse. But there are limits for using it online.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UyZoEcMV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqghg1z7149mg02wsfn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UyZoEcMV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqghg1z7149mg02wsfn3.png" alt="Recognition results comparison: server vs on-device. Source: Apple Tech Talks" width="800" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Phase 3: speech classification
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note: the main rule to using neural networks for speech classification is the more context there is, the better the accuracy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First things first, import the ML model to the project as a regular file. Next, create an instance of the model class. The file name will be the class name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;init?() { 
        do { 
            let config = MLModelConfiguration() 
            config.computeUnits = .all 
            if #available(iOS 16, *) { 
                config.computeUnits = .cpuAndNeuralEngine 
            } 
            mlModel = try ToxicTextClassificatorConditionalAlgoritm(configuration: MLModelConfiguration()).model 
            if let mlModel { 
                predicator = try NLModel(mlModel: mlModel) 
            } 
        } catch { 
            print("Can not initilaize ToxicTextClassificatorConditionalAlgoritm") 
            return nil 
        } 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NLModel - is the object you'll further work with.&lt;/p&gt;

&lt;p&gt;Once created, the model is ready to accept input text for classification.&lt;/p&gt;

&lt;p&gt;List the possible outcomes of the classification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;enum PredictResult: String { 
    case toxic 
    case positive 
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now try to get the result!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func predictResult(phrase: String) -&amp;gt; PredictResult? { 
        guard let predict = predicator?.predictedLabel(for: phrase), 
              let result = PredictResult(rawValue: predict) else { return nil } 
        return result 
   } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We analyze the phrase in real time. This means that the pieces that obtained in the second phase immediately fall into the classification. Because of this, the accuracy of the classification is inevitably lost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to enhance the results accuracy?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;а) If there is no punctuation, classify the text as it comes after the recognition and record the result. To do this, write a function that will accept the recognized text and flag that speech recognition is over.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reminder: the phase will contain more words each time for SFSpeechRecognitionResult returns the recognition results of the last audio buffer recognition along the results of all previous recognitions.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func analyze(phrase: String, isFinalResult: Bool) { 
        guard let predict = predictResult(phrase: phrase) else { 
            if isFinalResult, let result = predictResult { 
                event.onNext(.finalResult(result)) 
            } 
            return 
        } 
        predictResult = predict 
    } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b) If there's no punctuation* but you need to reduce the overhead for classification, you can only take the last N words from the sentence. However, this would greatly reduce the accuracy of the classification.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*To add automatic punctuation placement (currently only available in English):&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if #available(iOS 16.0, *) { 
            request?.addsPunctuation = true 
  } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To improve accuracy and reduce computation overhead, you can use the algorithm to divide text into sentences in proportion. For example, if there are 3 sentences in the text, do 2:1 or 1:2. That is, analyze the first 2 sentences first, then 1 remaining or first 1, then 2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--grlPWSLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xv7j5xlw0c49nw6r1wb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--grlPWSLe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xv7j5xlw0c49nw6r1wb.png" alt="Toxicity recognition results" width="800" height="1352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: It's necessary to request access to the mic and the permission for speech recognition.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative ways to get MLModel
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Tool set for Python CoreML tools, that allows converting models trained with other neural networks to mlmodel:&lt;/li&gt;
&lt;li&gt;CoreMl tools for TensorFlow&lt;/li&gt;
&lt;li&gt;CoreMl tools for PyTorch&lt;/li&gt;
&lt;li&gt;TensorFlow Lite for iOS. It allows working with models trained with TensorFlow.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can use neural networks for a plethora of different solutions. See how we work with it when &lt;a href="https://forasoft.com/blog/article/video-surveillance-software-development-375"&gt;developing video surveillance systems&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>webdev</category>
      <category>programming</category>
      <category>neuralnetwork</category>
    </item>
    <item>
      <title>Digital Payment Solutions: How to Choose a Provider &amp; 3 Ways to Earn</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Tue, 21 Feb 2023 19:09:45 +0000</pubDate>
      <link>https://forem.com/forasoft/digital-payment-solutions-how-to-choose-a-provider-3-ways-to-earn-3hc7</link>
      <guid>https://forem.com/forasoft/digital-payment-solutions-how-to-choose-a-provider-3-ways-to-earn-3hc7</guid>
      <description>&lt;p&gt;If you’re building a platform that involves payment processing, you’ll have to integrate a payment system into it. You need it to validate and store bank card information, process payments, and manage funds in general. &lt;/p&gt;

&lt;p&gt;A payment system will also let you accept payments in cryptocurrencies, including Bitcoin and Etherium. &lt;/p&gt;

&lt;p&gt;In the article, we talk about the online payment solutions you should choose for your digital product. And also explain how you can monetize your platform with it and how to choose the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need a payment processing provider for?
&lt;/h2&gt;

&lt;p&gt;They process all money transactions within your product: one-time purchases, subscription charges, etc. They mainly profit by retracting a fee from each transaction. &lt;/p&gt;

&lt;p&gt;It’s a big headache to switch between providers as it takes a lot of time and effort. So it’s crucial to pick “the one” from the very start.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose a payment service provider?
&lt;/h2&gt;

&lt;p&gt;When choosing a provider, you should take into account these three parameters:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your business’ country of registration&lt;/strong&gt;&lt;br&gt;
Every payment service provider works within a certain territory and might not be supported in some countries. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Stripe doesn’t work with businesses in the Cayman Islands. One of our clients had to register their enterprise in the USA for that reason&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;MangoPay only works within the European economic area&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;RazorPay only works in India. So if your company is registered in India and you’d like to expand internationally, you’ll have to integrate a new payment system.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: You should only consider YOUR company’s legal address. It doesn’t matter where the funds are coming from. This only defines the fee percentage. For instance, if you’re on Stripe, when your users pay with European cards, the fee is lower.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Payment systems&lt;/strong&gt;&lt;br&gt;
Payment systems are Visa, MasterCard, UnionPay, and others. There might also be some limitations considering the country that issued the card. But generally most cashless payment solution process the transactions from any Visa and MasterCard cards, in any currency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How your customers will pay you&lt;/strong&gt;&lt;br&gt;
That’s basically how your users will pay while / for using your product. Besides the usual way of paying with a credit card, you can integrate Apple or Google Pay into your platform. The fewer users need to do to pay the better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe vs PayPal vs others: pros and cons
&lt;/h2&gt;

&lt;p&gt;There’re plenty of payment service providers, each serving different needs. In the last 17 years, we have worked with many payment providers all over the globe. But now we recommend sticking with these 5 and here’s why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe&lt;/strong&gt;&lt;br&gt;
Simple yet powerful. Full stop. Stripe offers a wide range of functionalities that would fit any payment requirements: subscriptions, bonuses and coupons, advanced statistics and reports, and more. It’s also known as the most developer-friendly provider. Stripe would be a great choice for enterprises from the United States and Canada, but it works well for other countries as well. See &lt;a href="https://stripe.com/global" rel="noopener noreferrer"&gt;what countries Stripe works with&lt;/a&gt;. We in Fora Soft personally work with this provider the most.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PayPal&lt;/strong&gt;&lt;br&gt;
An alternative to Stripe but works &lt;a href="https://www.paypal.com/us/webapps/mpp/country-worldwide" rel="noopener noreferrer"&gt;in more countries&lt;/a&gt;, yet a bit less modern. It works well for the basics and is easy to set up, but it lacks agileness when it comes to customization. There’re also these major drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you cannot customize the checkout flow&lt;/li&gt;
&lt;li&gt;it’s impossible integrate Apple Pay, Microsoft Pay, and a number of other payment methods&lt;/li&gt;
&lt;li&gt;limited personalization: PayPal is simpler to set up, but it can’t be customized to fit your specific needs&lt;/li&gt;
&lt;li&gt;it’s costlier than Stripe&lt;/li&gt;
&lt;li&gt;no CRM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;MangoPay&lt;/strong&gt;&lt;br&gt;
Might be a good choice for businesses registered in Europe. The fee percentage is quite low and the payout is almost free. But you’ll have to waste a couple of hours on bureaucracy. For instance, in MangoPay a user can withdraw money to their bank account but they’ll have to use their ID or even an entire folder of docs if we’re talking businesses. Another drawback — you can’t connect MangoPay to neither Apple nor Google Pay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RazorPay&lt;/strong&gt;&lt;br&gt;
The best option for India, works only there, with Indian rupees. RazorPay is widely used in the country as it’s a quite reliable payment service provider. The one and only drawback is that you can’t connect it to Apple Pay. Feel free to integrate Google Pay though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Braintree&lt;/strong&gt;&lt;br&gt;
PayPal but a little bit more modern. Braintree offers more opportunities than the original system. For instance, it processes &lt;a href="https://newsbtc.com/all/ebay-and-paypal-to-accept-bitcoin-payments-through-braintree/" rel="noopener noreferrer"&gt;crypto currency operations&lt;/a&gt; and has &lt;a href="https://www.braintreepayments.com/lv/features/seamless-checkout/custom-ui?referrer=https%3A%2F%2Fwww.google.com%2F" rel="noopener noreferrer"&gt;additional customization tools&lt;/a&gt; for which you don’t have to overpay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monetization types and how to implement them
&lt;/h2&gt;

&lt;p&gt;The monetization type you want for your product depends on the business model you’ve picked for it: subscriptions, one-time payments, etc. Here are the most common ones:&lt;/p&gt;

&lt;h3&gt;
  
  
  One-time payment
&lt;/h3&gt;

&lt;p&gt;Would work well with, for instance, online movie lease (like in &lt;a href="https://forasoft.com/project/janson-media-internet-tv" rel="noopener noreferrer"&gt;Vodeo&lt;/a&gt;), online stores, or any service where users have to pay for each unit. &lt;/p&gt;

&lt;p&gt;For web platforms one-time payment works in 2 possible scenarios:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Request user data within the platform sent it to the provider, and receive and display the response. A few nuances:&lt;/li&gt;
&lt;li&gt;You’ll have to spend much time for a decent UI that will not only look good but will also display the errors correctly.&lt;/li&gt;
&lt;li&gt;Users might not trust a new platform that asks for their bank details&lt;/li&gt;
&lt;li&gt;Forward users to the checkout page by a known payment service provider. You might have experienced it yourself when you push that “Pay” button and here you are on a completely different page asking for your card details.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What’s good about it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;integrating checkout takes less time than developing your own page from scratch = saves you money&lt;/li&gt;
&lt;li&gt;Apple and Google Pay support&lt;/li&gt;
&lt;li&gt;users can manage their coupons and discounts, taxes like VAT, etc.&lt;/li&gt;
&lt;li&gt;you can customize the checkout page if necessary
What your users can’t do though is save their card details for further fast purchases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it looks like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbljf5y5xm4btvcppe4bf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbljf5y5xm4btvcppe4bf.png" alt="Stripe Checkout page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vv5pamdraxlg2b80tt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7vv5pamdraxlg2b80tt1.png" alt="MangoPay checkout page" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Subscription
&lt;/h3&gt;

&lt;p&gt;Users pay for a certain period they have access to the platform and a certain bunch of features, depending on the plan.&lt;/p&gt;

&lt;p&gt;There’re 2 ways to implement this monetization plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;on your own, within the platform &lt;/li&gt;
&lt;li&gt;with Stripe Checkout 
Integrating it into your product is easier and quicker than developing your own. Stripe Checkout is a complex payment processing system that also works well for subscriptions. Yet, it definitely can cover all the requirements your product might have. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Stripe Checkout you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set the price, trial period, payment frequency&lt;/li&gt;
&lt;li&gt;Keep track of the subscription status (paid / not paid)&lt;/li&gt;
&lt;li&gt;Add Stripe Customer Portal to have your users manage their subscription and change the payment method on their own&lt;/li&gt;
&lt;li&gt;Set the scheduled payments &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why reinvent the wheel?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaxvwvd5ianfkd69ept9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzaxvwvd5ianfkd69ept9.png" alt="Paying for a subscription on Stripe" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjylm7wf0q3qj7voxh8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjylm7wf0q3qj7voxh8e.png" alt="Managing your subscriptions on Stripe" width="768" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  User-to-user or Platform-to-user
&lt;/h3&gt;

&lt;p&gt;Marketplaces, online workout services, and any other products where a platform “pays” to its users are usually on this monetization type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There’re two parts to the process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Money gets into the system&lt;/li&gt;
&lt;li&gt;It gets out. Easy, right?
We all know what happens with the first step: a user enters their card details within the system or on the checkout page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To make the second part happen you can either develop it manually or use a ready-made solution. We usually go with the latter and pick Stripe Connect.&lt;/p&gt;

&lt;p&gt;But as a third-party solution, it has limitations. When making a transaction both your platform and the user have to be registered in the same country. International transfers are only available for companies registered in the USA.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to accept crypto payments as a business?
&lt;/h2&gt;

&lt;p&gt;Many companies including &lt;a href="https://cointelegraph.com/explained/who-accepts-bitcoin-as-payment" rel="noopener noreferrer"&gt;Virgin Airlines, Microsoft and others&lt;/a&gt; accept cryptocurrency payments. But not all payment service providers are ready to process them for the lack of security.&lt;/p&gt;

&lt;p&gt;However based on what &lt;a href="https://support.stripe.com/express/questions/crypto-payouts" rel="noopener noreferrer"&gt;Stripe itself&lt;/a&gt; and &lt;a href="https://www.bloomberg.com/news/articles/2022-05-24/stripe-to-resume-accepting-bitcoin-payments-in-crypto-push#:~:text=Using%20the%20app%2C%20Stripe%20customers,of%20their%20balance%20into%20Bitcoin." rel="noopener noreferrer"&gt;Bloomberg&lt;/a&gt; claim, the named platform processes payments in at least 2 cryptocurrencies: Bitcoin and Ethereum.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://newsroom.paypal-corp.com/2022-06-07-PayPal-Users-Can-Now-Transfer-Send-and-Receive-Bitcoin-Ethereum-Bitcoin-Cash-and-Litecoin#:~:text=Transferring%20crypto%20into%20PayPal%20from,any%20additional%20ID%20verification%20steps." rel="noopener noreferrer"&gt;PayPal&lt;/a&gt; and &lt;a href="https://newsbtc.com/all/ebay-and-paypal-to-accept-bitcoin-payments-through-braintree/" rel="noopener noreferrer"&gt;Braintree&lt;/a&gt; work with cryptocurrencies as well. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final words and recommendations
&lt;/h2&gt;

&lt;p&gt;We’ll be glad to come up with a specific solution picked individually for your project. &lt;a href="https://forasoft.com/contacts" rel="noopener noreferrer"&gt;Contact us&lt;/a&gt; to discuss your ideas.&lt;/p&gt;

&lt;p&gt;And if you’d like to decide on your own here, you want to base your decision on 4 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;your business’ country of registration&lt;/li&gt;
&lt;li&gt;payment methods and systems&lt;/li&gt;
&lt;li&gt;availability of cryptocurrency operations&lt;/li&gt;
&lt;li&gt;monetization type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our general recommendation for most systems would be turning for a checkout page instead of developing an own one. Going with a highly customizable solution (like Stripe, for example) will ensure you have a flawlessly working page that looks the way you need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng2uj460n81limmr9vta.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fng2uj460n81limmr9vta.gif" alt="Stripe checkout page. Source: Stripe" width="760" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only possible drawback here is that there’ll be a provider’s logo. But that’s the price you pay for reliable solution, saved time and budget, as well as better user experience.&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>Using SDK vs Custom Development. Guide For Software and App Founders</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Tue, 14 Feb 2023 08:30:00 +0000</pubDate>
      <link>https://forem.com/forasoft/using-sdk-vs-custom-development-guide-for-software-and-app-founders-3gmk</link>
      <guid>https://forem.com/forasoft/using-sdk-vs-custom-development-guide-for-software-and-app-founders-3gmk</guid>
      <description>&lt;p&gt;When building own multimedia and communication software there always stands a question. Shall I use a ready-made solution like an SDK or API or shall I develop my own custom component? What approach would be more beneficial in the long run? What do I need to take into account to make the right choice?&lt;/p&gt;

&lt;p&gt;So here is an article that clears things out to help you make the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is an SDK?
&lt;/h2&gt;

&lt;p&gt;First, let’s figure out clearly what we are talking about. An &lt;strong&gt;SDK is a set of software development tools developers can use as ready-made solutions&lt;/strong&gt; building software for specific platforms. SDKs can include one or more APIs along with programming tools and documentation. This means that this will still require developers’ effort to assemble and integrate the component but not write it from scratch. That means less development time and money paid. Some development teams prefer certain SDK’s because they are familiar to them, but it might not be the best choice for the platform. &lt;/p&gt;

&lt;h2&gt;
  
  
  How to pick the right SDK?
&lt;/h2&gt;

&lt;p&gt;Here is a set of parameters to check for each SDK you consider: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;API and SDK documentation — whether it is clear and easy to understand for developers. If it’s not, it will lead to a higher cost of integration for an increase in the developer time and effort.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tech stack. That is languages and frameworks used on your platform and whether there is documentation for these. Paid APIs and SDKs provide documentation for the majority of languages and frameworks. It’s not the case with free APIs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Support. How well the company provides technical support in case there are difficulties in setting up the component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reliability. You want the provider to offer the SLA (service level agreement) is around 99.99%, meaning the system will work 99.99% of the time. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability limits. Some components do not allow for a large number of concurrent users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security. Video and text-based chat content is of a sensitive nature. For that video APIs must meet the highest data security standards. When you integrate them, you also integrate top-level compliance — something else your app developers won’t need to worry about, that saves a lot of time. Yet it mostly works for paid SDKs only.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Сode license of the component. If the SDK you’re using is licensed under GPL2 / GPL3, you’ll be obliged to share the source code of your whole system available on request. That means any developer can ask for the code to your product and use it for free.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regional support — whether service providers work in the country you target. For instance, Twilio works in 50 countries, while Vonage is checked successfully for 80 countries.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cons of SDK for multimedia and engagement features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It saves time for development as it provides the pre-built functionality. Otherwise you’d have to build it from scratch. This, in turn, speeds up time to market for your &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263" rel="noopener noreferrer"&gt;MVP&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It provides a consistent and stable development environment. So it’s easier to keep your software code up to date.&lt;/li&gt;
&lt;li&gt;It facilitates the integration of new features and functionalities into applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It limits flexibility and customization options for developers. They will have to work within the constraints of the SDK. For instance, certain AR video editing SDKs won’t let you upload your own face effects. Some whiteboard SDKs don’t allow attaching video files. Or, there’re SDKs that work with sound but don’t have facilities to make a certain audio protocol setup for undistorted sound. &lt;/li&gt;
&lt;li&gt;It may not provide all the features or functionality that a developer needs for a specific application. For example, adding a formula editor to a whiteboard component. So a paid solution might still require &lt;a href="https://forasoft.com/services" rel="noopener noreferrer"&gt;custom development&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;It brings extra monthly costs. If your platform grows faster than you expected you may find yourself spending more on supporting the load of users with an SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to know you need to go for custom development
&lt;/h2&gt;

&lt;p&gt;Answer these 3 questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How complex is the functionality of the component that your business requires?&lt;/strong&gt; Do you want a simple one-on-one text chat or an entire LMS system? What particular features do you expect your product to have? Complexity of the functionality is evaluated on the planning stage, when business requirements are figured. This may vary from a simple one-on-one text chat functionality to a whiteboard component for presentations, custom participant roles or making unique setup for a clear sound quality in a collaboration tool for musicians or application of a particular codec, FPS or streaming protocol. Most engagement SDKs on the market offer basic features: voice calling, text, p2p and group video chat, or streaming. Although there are providers that offer a variety of complex features such as speech-to-text transcription, recording and cloud storage functionality and custom whiteboard components. Each of these components increases the price of the SDK on per usage dramatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;How many overall or simultaneous users should your system support?&lt;/strong&gt; Some multimedia and engagement SDKs have limitations to the number of concurrent rooms and users of the service. There’re limits for calls, conferences, streams and chats. They usually define and limit the number of participants in a chat room or a video call, a number of concurrent watchers of a stream. If you require larger numbers then those the SDK offers you’ll have to scale it up. This takes lots of effort and requires custom development.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Are you ready to overpay the monthly upkeep costs for your system?&lt;/strong&gt;&lt;br&gt;
Let’s take an example to see the difference, as features are added.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We have requirements for a simple group meeting of 5 people with video quality 480p. The meeting must run for one hour. Based on our records, the cost of handling this meeting through an SDK is ~ $1,2 per hour. With a custom component that will be $0,69 per hour. &lt;br&gt;
Also, the project requires a recording feature. It increases the cost of a meeting with SDK to ~$2,4 per hour. For the custom component it’ll only make 7 cents difference — the overall cost will be $0,75 per hour.&lt;br&gt;
Meeting recordings often require cloud storage for multiple users access. That’s another expense item. Check out how to &lt;a href="https://forasoft.com/blog/article/how-to-estimate-the-server-cost-for-a-video-platform-249" rel="noopener noreferrer"&gt;calculate the size of a video file&lt;/a&gt;.&lt;br&gt;
Based on our inputs, the meeting requires 13,72GB of storage. Now the cost of a meeting with SDK will be ~$3,04 per hour and will only cost $0,81/hour with a custom component.&lt;br&gt;
We can also see the difference for a speech-to-text recognition. $4,96 per hour with an SDK vs $2,25 per hour with a custom component.&lt;/p&gt;

&lt;p&gt;So, here is what we get for one meeting. Using an &lt;strong&gt;SDK is twice as expensive to upkeep&lt;/strong&gt;. However, it’s not that bad. For 500 meetings a month it will be ~$2480 vs $1125 for our example case. This &lt;strong&gt;monthly overpayment will have to go on for at least 3 years to cover expenses&lt;/strong&gt; for custom development. If you are a startup that is testing out a market hypothesis and only building an MVP, then you are not expecting big numbers just yet. And this difference in the upkeep costs will not cover the initial investment to make a custom component. Also, some SDK providers offer discounts and limited free usage for startups.&lt;/p&gt;

&lt;p&gt;But if the system is large and you expect, say 5000 meetings a month, the difference in the upkeep costs is dramatic. &lt;strong&gt;Custom development will pay off in half a year and cut down your costs.&lt;/strong&gt; The same works for all multimedia components — voice calls, text chats, streaming, video player and others.&lt;/p&gt;

&lt;p&gt;To sum up, the choice between custom development and using an SDK involves multiple parameters to evaluate as well as prospects for the system growth. SDKs usually are a good choice for MVPs, if communication services is not the main benefit of the platform, but rather an upgrade to the main USP.&lt;/p&gt;

</description>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Top 6 Online and Offline Investment Sources for Your Software</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Mon, 13 Feb 2023 09:17:00 +0000</pubDate>
      <link>https://forem.com/forasoft/top-6-online-and-offline-investment-sources-for-your-software-4of7</link>
      <guid>https://forem.com/forasoft/top-6-online-and-offline-investment-sources-for-your-software-4of7</guid>
      <description>&lt;p&gt;You have an idea for a product. You don’t have anything else. Where to get money for your project? Will you really get some? What if you also need business advice along the way?&lt;/p&gt;

&lt;p&gt;This article will answer your questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  There are three types of investment seekers
&lt;/h2&gt;

&lt;p&gt;If we’re talking startups, founders seeking investment usually fall into two categories. Each has its own investment options. Let’s see which one you are.&lt;/p&gt;

&lt;h3&gt;
  
  
  You have a general idea of what the product is going to be but you haven’t worked through the details
&lt;/h3&gt;

&lt;p&gt;It all starts with an idea. If you have it already but are still not sure about the details, look into &lt;strong&gt;Angel Investment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An angel investor (they’re also called private investors, seed investors) is basically a wealthy person who can provide financial support for a small business or an entrepreneur for ownership stock in the firm. The percentage is usually up to 25% but can reach as much as 40% or more. It may be a one-time investment or continuous money infusion. &lt;/p&gt;

&lt;p&gt;Angels invest in the products that are just starting off and use their own money for that. So basically any rich person can become an angel investor. However, these are high-risk investments that should not exceed 10% of an angel investor’s portfolio. Meaning they can’t spend more than 10% of their net worth on the investing. &lt;/p&gt;

&lt;p&gt;Angel investors usually also have the industry expertise: they’ve most likely made the money they have themselves by running a business successfully. So they can also give you business advice and guidance in your entrepreneurship as well as be a one of the key participants of the decision making process if their share allows them to. &lt;/p&gt;

&lt;p&gt;To find an angel you don’t necessarily need an old rich aunt or Jeff Bezos as your friend &lt;/p&gt;

&lt;p&gt;Try these: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.angellist.com/" rel="noopener noreferrer"&gt;Angellist&lt;/a&gt; — a free tool to find angel investors or even first employees for your startup. One of the first businesses to seek out angels on Angellist was Uber, in 2010.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.angelinvestmentnetwork.us/network" rel="noopener noreferrer"&gt;Angel Investment Network&lt;/a&gt; — kind of a marketplace to connect startups with investors.&lt;/li&gt;
&lt;li&gt;Social media — tell about your ideas on your Twitter or LinkedIn and ask your contacts to share the info. &lt;a href="https://en.wikipedia.org/wiki/Six_degrees_of_separation" rel="noopener noreferrer"&gt;Six degrees of separation&lt;/a&gt; and &lt;a href="https://news.stanford.edu/2022/09/15/real-strength-weak-ties/" rel="noopener noreferrer"&gt;the power of weak ties&lt;/a&gt; are real!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Another category is:&lt;/p&gt;

&lt;h3&gt;
  
  
  You have a detailed idea description and solid understanding of how it will work
&lt;/h3&gt;

&lt;p&gt;For when you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;know exactly what you and your business need&lt;/li&gt;
&lt;li&gt;you know you will grow fast and investors will see it too
Go venture!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Venture capitalists&lt;/strong&gt; provide funding to startups and small businesses with seen long-term development potential. You can get venture capital from wealthy individual investors, investment banks, or other financial organizations. &lt;/p&gt;

&lt;p&gt;What’s special about VC is that it’s not necessarily money. It can be strong managerial powers or, for instance, technical expertise and skills. &lt;/p&gt;

&lt;p&gt;This is a quite risky type of money allocation for investors, but the prospect for above-average profits is appealing. In most cases venture investors tend to finance high-tech projects, pharma, health, or some kind of brand new idea — anything with &lt;strong&gt;extraordinary growth potential&lt;/strong&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Here is what you need to do to win investment from a VC:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Identify venture capital firms that invest in businesses similar to yours. You can go both ways: research into what VC funded your concurrent and competitor businesses or look into what startups particular VC invest into. Try &lt;a href="https://www.cbinsights.com/" rel="noopener noreferrer"&gt;CB Insights&lt;/a&gt; — it’s a highly-regarded resource that offers data on active VC firms and associated industries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that the company invests in the stage of funding that you require. Some VC might be looking to fund startups with nothing but an idea and a plan, some only invest into small businesses with an MVP and strong growth potential. Most venturing organizations provide that info along with pitch requirements on their website. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Investigate the firm’s previous deals. This way you can see whether the VC you’ve picked provides the exact type of investment you seek and you don’t get a management team instead of $50k. The research method is the same as in point 1, the info is quite transparent. Or try &lt;a href="https://www.crunchbase.com/" rel="noopener noreferrer"&gt;Crunchbase&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prepare your pitch presentation. You need to literally sell your idea to the investors. Here’s what you should cover.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Your target audience
Describe it as detailed as possible. Include the clear definition of the segment and the TA’s known peculiarities — you must demonstrate you know them well. But don’t confuse “detailed” and “narrow”. Being too specific is not always an advantage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should also research into your TA. The more client-oriented you are, the better. Try out field study for that. &lt;br&gt;
Problem, solution, and product image. Use prototypes, designs, or demo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Technology / Innovation&lt;br&gt;
You should transparently and clearly show what technology / approach / innovation you put in the base, how it will help you take over the competition, what the value is and how this exact technology / approach / innovation serves your TA’s needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Monetization model&lt;br&gt;
This is how you plan to make money with your product and how realistic it is to make money off the product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Team and implementation&lt;br&gt;
With this info you should prove you’re well aware of what key roles you need to cover in your team to get to the result. Show your current opportunities and strong understanding of the resources it requires.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How realistic it is to enter the market&lt;br&gt;
Explain why you feel your strategy matches the product goals and showcase how well you understand the steps you need to take to get there.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  You need a mentor, a network, and support in building your business
&lt;/h3&gt;

&lt;p&gt;No matter what stage you are at, business incubators might be a good solution for you.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;business incubator&lt;/strong&gt; is an &lt;strong&gt;organization that helps entrepreneurs develop and succeed&lt;/strong&gt; by providing a variety of business support tools and services such as physical space, financing, coaching, shared services, and networking connections.&lt;/p&gt;

&lt;p&gt;Private corporations, municipalities, and public organizations such as universities and colleges frequently support business incubation programs. Their mission is to assist in the formation and growth of new firms by providing them with the required resources, including financial and technical assistance. Their office and manufacturing space is available at below-market prices, and their team provides valuable assistance and expertise in building business and marketing plans, as well as assisting in the funding of new ventures. &lt;/p&gt;

&lt;p&gt;Firms often stay in a business incubator for two years, during which time they sometimes share telephone, secretarial office, and production equipment expenditures with other new companies in an effort to lower operational costs.&lt;/p&gt;

&lt;h4&gt;
  
  
  To find an incubator
&lt;/h4&gt;

&lt;p&gt;Try the &lt;a href="https://incubatorlist.com/" rel="noopener noreferrer"&gt;IncubatorList&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The main thing to remember — look for incubators in your location and for your segment, since there are narrowly specialized incubators: for education, medicine, or even supporting women). Pay attention to what the incubator wants in return, how much it costs, if there were successful alumni, or if it’s university based.&lt;/p&gt;

&lt;h2&gt;
  
  
  There’re investment seeking strategies that work well for all three types
&lt;/h2&gt;

&lt;p&gt;Anyone who thinks your idea is valuable enough to generate ROI (return on investment) might help. So fundraise! Here’re possible strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Friends &amp;amp; Family&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don’t underestimate your close ones. They know and believe you, so this money is easy to attract. Outside investors need proof you’re serious. But another thing here — if you’re not ready to risk your own and your close ones’ money, you are probably not.&lt;/p&gt;

&lt;p&gt;Mail chimp and Github bootstrapped themselves. &lt;a href="https://techstartups.com/2018/03/04/successful-bootstrapped-startups-10-profitable-startups-started-little-no-money/" rel="noopener noreferrer"&gt;See who else&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Crowdfunding&lt;/strong&gt;&lt;br&gt;
Make a million stranges who believe in your idea donate a dollar. How to do that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a campaign&lt;/li&gt;
&lt;li&gt;Make the content to engage people&lt;/li&gt;
&lt;li&gt;Set up and launch the campaign&lt;/li&gt;
&lt;li&gt;Promote campaign: e.g. on social media&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reward-based crowdfunding&lt;/strong&gt;&lt;br&gt;
It’s a form of crowdfunding when people donate money to your project and expect to get a non-monetary benefit in return: a lifetime subscription, a merch, or something else. &lt;/p&gt;

&lt;p&gt;Where to crowdfund reward-based:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.kickstarter.com/" rel="noopener noreferrer"&gt;Kickstarter&lt;/a&gt;
Crowdfunding platform for creative community. You might want to place your project campaign in the Technology category. There are subcategories for &lt;a href="https://www.kickstarter.com/discover/advanced?category_id=332&amp;amp;sort=magic&amp;amp;seed=2755080&amp;amp;page=1" rel="noopener noreferrer"&gt;apps&lt;/a&gt;, &lt;a href="https://www.kickstarter.com/discover/advanced?category_id=51&amp;amp;sort=magic&amp;amp;seed=2755080&amp;amp;page=1" rel="noopener noreferrer"&gt;software&lt;/a&gt;, and &lt;a href="https://www.kickstarter.com/discover/advanced?category_id=342&amp;amp;sort=magic&amp;amp;seed=2755080&amp;amp;page=1" rel="noopener noreferrer"&gt;web services&lt;/a&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.forasoft.com%2Fwp-content%2Fuploads%2F2022%2F11%2FKick-starter-Fees-calculator.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.forasoft.com%2Fwp-content%2Fuploads%2F2022%2F11%2FKick-starter-Fees-calculator.png" alt="Kickstarter Fees calculator" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The mechanic is All or nothing: &lt;/p&gt;

&lt;p&gt;set your objective you’re seeking to crowdfund (try their &lt;a href="https://docs.google.com/spreadsheets/d/1pR_ooiAD-7M93YW1mE8lu8VULRJd6nI5nORECyBKwv8/edit#gid=0" rel="noopener noreferrer"&gt;template for objective estimation&lt;/a&gt; in .xls). If you don’t get it, all the money goes back to the backers and you get nothing.&lt;br&gt;
define the rewards for backers: lifetime subscription, a merch we’ve mentioned before, or an event pass, etc. You can’t set equity as a reward. &lt;br&gt;
set the campaign period — 1 to 90 days. The most effective period proves to be 30 days. The limited time period creates urgency and motivates your community to back your project and spread the word.&lt;br&gt;
Your or your business address must be located in one of the &lt;a href="https://help.kickstarter.com/hc/en-us/articles/115005128594-Who-can-use-Kickstarter-" rel="noopener noreferrer"&gt;listed countries&lt;/a&gt; and have a bank account that meets the &lt;a href="https://help.kickstarter.com/hc/en-us/articles/115005136114-What-type-of-bank-account-can-I-use-to-set-up-my-project-" rel="noopener noreferrer"&gt;platform requirements&lt;/a&gt;. And make sure you project is none of &lt;a href="https://www.kickstarter.com/rules/prohibited?ref=project_build" rel="noopener noreferrer"&gt;this&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;If a project is successfully funded, Kickstarter collects a 5% fee from the funds collected for creators. Stripe, the payments processor, will also collect a payment processing fee (roughly 3-5%). The complete fee breakdowns are available &lt;a href="https://www.kickstarter.com/help/fees?ref=faq-basics_fees" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.forasoft.com%2Fwp-content%2Fuploads%2F2022%2F11%2FKick-starter-project-set-up.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.forasoft.com%2Fwp-content%2Fuploads%2F2022%2F11%2FKick-starter-project-set-up.png" alt="Kickstarter project set up page" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it a good idea to crowdfund on Kickstarter?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Can start promotion before everything’s ready by creating Pre-launch page &lt;br&gt;
Potential backers will be able to find it on Kickstarter, but you should share your pre-launch page with everyone to create excitement and attention around your project before you launch it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Connect Google Analytics to the campaign.&lt;br&gt;
That means you can advertise on YouTube, Google search, or the affiliated website with Google ads.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.indiegogo.com/" rel="noopener noreferrer"&gt;Indiegogo&lt;/a&gt; 
Your project might fit into Tech&amp;amp;Innovation category with &lt;a href="https://www.indiegogo.com/explore/education" rel="noopener noreferrer"&gt;Education&lt;/a&gt;, &lt;a href="https://www.indiegogo.com/explore/health-fitness" rel="noopener noreferrer"&gt;Health &amp;amp; Fitness&lt;/a&gt;, &lt;a href="https://www.indiegogo.com/explore/productivity" rel="noopener noreferrer"&gt;Productivity&lt;/a&gt; subcategories. Indiegogo is mostly for tangible products, yet you still can try crowdfund your software there. Here’s what a successful software campaign is like on Indiegogo: &lt;a href="https://www.indiegogo.com/projects/fluent-forever-app-think-in-any-new-language/x/25294940#/" rel="noopener noreferrer"&gt;Fluent Forever App: THINK In Any New Language&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check out the &lt;a href="https://support.indiegogo.com/hc/en-us/articles/115002299827-How-do-I-choose-my-bank-account-country-country-of-legal-residence-and-currency-" rel="noopener noreferrer"&gt;legal address and bank account requirements&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;How much can you raise?&lt;/p&gt;

&lt;p&gt;Indiegogo offers two funding types: Flexible Funding (keep what you raise) and Fixed Funding (all-or-nothing). Learn about &lt;a href="https://support.indiegogo.com/hc/en-us/articles/205138007" rel="noopener noreferrer"&gt;the differences and the pricing&lt;/a&gt; for each.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.kisskissbankbank.com/fr/projects/application-tolvek]" rel="noopener noreferrer"&gt;Kisskissbankbank&lt;/a&gt;
It’s a French crowdfunding platform where you can finance your project with &lt;strong&gt;regular support&lt;/strong&gt; of your community. Choose a &lt;strong&gt;monthly or quarterly recurrence and create your own subscription formulas&lt;/strong&gt;, offer exclusive content to your contributors and finance the sustainability of your project over the long term!&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Equity crowdfunding
&lt;/h3&gt;

&lt;p&gt;It is a form of fundraising where you attract investors that contribute funds toward your business goals in return for a financial stake in the company. You can also allow them into the product making process depending on their investment like voting on marketing or development matters. &lt;/p&gt;

&lt;h4&gt;
  
  
  Where to equity crowdfund:
&lt;/h4&gt;

&lt;p&gt;Depending on where you and your business are located, you might want to try one of these platforms:&lt;/p&gt;

&lt;p&gt;Worldwide&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.equitynet.com/" rel="noopener noreferrer"&gt;Equitynet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fundrazr.com/pages/countries-currencies" rel="noopener noreferrer"&gt;Fundrazr&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ourcrowd.com/" rel="noopener noreferrer"&gt;Ourcrowd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Canada&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://equivesto.com/" rel="noopener noreferrer"&gt;Equivesto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.frontfundr.com/" rel="noopener noreferrer"&gt;Frontfundr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://vested.ca/" rel="noopener noreferrer"&gt;Vested&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ulule.com/categories/technology/" rel="noopener noreferrer"&gt;Ulule&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.canadastartups.org/" rel="noopener noreferrer"&gt;Сanadastartups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.lendingloop.ca/" rel="noopener noreferrer"&gt;Lending Loop&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;USA &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.startengine.com/" rel="noopener noreferrer"&gt;Startengine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fundable.com/" rel="noopener noreferrer"&gt;Fundable&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wefunder.com/explore/tech" rel="noopener noreferrer"&gt;Wefunder&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://netcapital.com/" rel="noopener noreferrer"&gt;Netcapital&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fundify.com/" rel="noopener noreferrer"&gt;Fundify&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://bioverge.com/" rel="noopener noreferrer"&gt;Bioverge&lt;/a&gt; (healthcare startups)
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UK&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.crowdcube.com/" rel="noopener noreferrer"&gt;Crowdcube&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.seedrs.com/" rel="noopener noreferrer"&gt;Seedrs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crowdforangels.com/" rel="noopener noreferrer"&gt;Crowd for Angels Ltd.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.growthcapitalventures.co.uk/" rel="noopener noreferrer"&gt;GrowthFunders&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Europe&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Germany: &lt;a href="https://www.companisto.com/de" rel="noopener noreferrer"&gt;Companisto&lt;/a&gt;, &lt;a href="https://www.seedmatch.de/" rel="noopener noreferrer"&gt;Seedmatch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Romania: &lt;a href="https://seedblink.com/" rel="noopener noreferrer"&gt;Seedblink&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Spain: &lt;a href="https://startupxplore.com/" rel="noopener noreferrer"&gt;Startupxplore&lt;/a&gt;, &lt;a href="https://capitalcell.es/" rel="noopener noreferrer"&gt;Capitalcell&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;France: &lt;a href="https://www.wiseed.com/" rel="noopener noreferrer"&gt;WiSeed&lt;/a&gt;, &lt;a href="https://sowefund.com/" rel="noopener noreferrer"&gt;Sowefund&lt;/a&gt;, &lt;a href="https://www.happy-capital.com/" rel="noopener noreferrer"&gt;Happy Capital&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Estonia: &lt;a href="https://www.funderbeam.com/" rel="noopener noreferrer"&gt;Funderbeam&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Sweden: &lt;a href="https://www.fundedbyme.com/en/" rel="noopener noreferrer"&gt;Fundedbyme&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Finland / Sweden: &lt;a href="https://www.invesdor.com/" rel="noopener noreferrer"&gt;Invesdor&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;The Netherlands: &lt;a href="https://www.leapfunder.com/" rel="noopener noreferrer"&gt;Leapfunder&lt;/a&gt;, &lt;a href="https://www.symbid.com/" rel="noopener noreferrer"&gt;Symbid&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Austria: &lt;a href="https://www.greenrocket.com/" rel="noopener noreferrer"&gt;Green Rocket&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Belgium: &lt;a href="https://crowdfunding.bolero.be/" rel="noopener noreferrer"&gt;Bolero&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Middle East&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Israel: &lt;a href="https://www.exitvalley.com/" rel="noopener noreferrer"&gt;ExitValley&lt;/a&gt;, &lt;a href="https://en.tgt.co.il/" rel="noopener noreferrer"&gt;Together&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;UAE: &lt;a href="https://bambucorn.com/" rel="noopener noreferrer"&gt;Bambucorn&lt;/a&gt;, &lt;a href="https://www.beehive.ae/" rel="noopener noreferrer"&gt;Beehive&lt;/a&gt;,  &lt;a href="https://www.dubainext.ae/explore?category=15&amp;amp;category=9" rel="noopener noreferrer"&gt;Dubainext&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Palestine: &lt;a href="https://buildpalestine.com/about-us/" rel="noopener noreferrer"&gt;Buildpalestine&lt;/a&gt;,
&lt;/li&gt;
&lt;li&gt;Malaysia: &lt;a href="https://ethis.co/" rel="noopener noreferrer"&gt;Ethis&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Initial coin offering
ICO is a form of investment where funds are raised with cryptocurrency venture. How to get into ICO:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Create your white paper — basically your idea / project description and all its aspects that might potentially catch investors’ interest. Make sure it’s well designed and is truly appealing as an investment opportunity.&lt;br&gt;
Publish it on any cryptocurrency stock market (e.g. Binance) and promote it.&lt;br&gt;
Get crypto donations (mostly in Ethereum) from backers. They’ll get project’s tokens in return.&lt;br&gt;
Once your project succeeds the backers can sell their tokens and profit, so in case of your success it’s a win-win situation.&lt;/p&gt;

&lt;p&gt;Here’s &lt;a href="https://imiblockchain.com/best-ico-websites-review/" rel="noopener noreferrer"&gt;top 10 most recommended platforms for ICO&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Bad news: ICO involves a lot of risk taking. Good news: risks are mostly for the backers. &lt;/p&gt;

&lt;p&gt;Listing an ICO is not free, though. &lt;a href="https://appinventiv.com/blog/cost-of-launching-ico/" rel="noopener noreferrer"&gt;Rough estimates&lt;/a&gt; are in the range of $40,000 to $200,000.    &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You might be seeking investment on different stages of your project development. The first one here can be building an &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263" rel="noopener noreferrer"&gt;MVP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And if you already have one and are seeking further stages funding, here’s what you should probably &lt;a href="https://forasoft.com/blog/article/what-should-come-after-the-1st-mvp-release-for-it-to-be-a-success-1287" rel="noopener noreferrer"&gt;allocate budget to&lt;/a&gt; before you spend a penny on the actual development. &lt;/p&gt;

&lt;p&gt;Did you find this list useful? Let us know in the comments&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>productivity</category>
      <category>devworkflows</category>
    </item>
    <item>
      <title>Moodle VS Custom Development: What’s Best For Your E-learning Product</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Thu, 03 Nov 2022 06:28:01 +0000</pubDate>
      <link>https://forem.com/forasoft/moodle-vs-custom-development-whats-best-for-your-e-learning-product-5c3o</link>
      <guid>https://forem.com/forasoft/moodle-vs-custom-development-whats-best-for-your-e-learning-product-5c3o</guid>
      <description>&lt;p&gt;You might feel on the crossroad when planning out your &lt;a href="https://forasoft.com/services/e-learning"&gt;e-learning platform&lt;/a&gt;. “Do I need it to be custom developed from scratch? Or can I save up by using a ready-made solution? What risks are there?” In this article we will share our experience to answer you questions. &lt;/p&gt;

&lt;p&gt;Our clients ask us about Moodle so let’s use it as an example. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is Moodle?
&lt;/h2&gt;

&lt;p&gt;As the name suggests — Modular Object-Oriented Dynamic Learning Environment Learning Management System — Moodle is a system made to manage e-learning processes. Educational institutions use it in 243 countries on 180 thousand websites with overall 312 million users.&lt;/p&gt;

&lt;p&gt;On Moodle you can create your own courses, post news, assign tasks, make electronic journals, develop your own tests, etc. It’s an agile and freetool with lots of additional plugins that help you install any software your users might need. &lt;/p&gt;

&lt;p&gt;So if there’s a tool like this, why even bother developing your own e-learning platform which takes time and requires more money? Here’s a quick overview:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NacfDZXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jpo1bsz7979hdp3yrpp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NacfDZXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jpo1bsz7979hdp3yrpp.png" alt="Moodle and custom development comparison table" width="880" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I know Moodle is enough for me?
&lt;/h2&gt;

&lt;p&gt;There are cases when you can save up a lot of money by just building your courses in Moodle. It is when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need the platform for internal use&lt;/li&gt;
&lt;li&gt;Custom UI design adapted to your branding is not a priority&lt;/li&gt;
&lt;li&gt;You’re on a low budget&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moodle truly does have some benefits.&lt;/p&gt;

&lt;p&gt;Firstly, it’s an OSS (Open Source Software). That means you can install, use, modify, and share results of your interaction with Moodle for free in compliance with &lt;a href="https://ru.wikipedia.org/wiki/GNU_General_Public_License"&gt;GNU (General Public License)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Secondly, Moodle works on most servers that support PHP. Users can install, use, and update it on any device.&lt;/p&gt;

&lt;p&gt;Thirdly, millions of people use Moodle to build their first products worldwide, meaning there’re always other users to help on forums, and there’s also a set of plugins for most basic functionalities: building courses, video conferencing, tests, assigning hometasks.  &lt;/p&gt;

&lt;p&gt;Finally, there’s detailed documentation that will be very much instrumental when installing and using Moodle. And if you can’t find answers to your questions there, you can always get it on a forum. &lt;/p&gt;

&lt;p&gt;What issues you are probably going to have &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Long time to solve tech issues&lt;/strong&gt;
Moodle does have detailed documentation. And if you have questions, you’ll have to get them yourself. There’s no customer support team for Moodle, which &lt;strong&gt;makes problem solving quite complicated.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Difficulties in using plugins&lt;/strong&gt;
Moodle has various plugins and features that can cover almost any e-learning need. But there’s no clear instructions for how to use plugins to customize your platform. Most of the plugins are free, but some cost extra money.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Need for an admin&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Moodle requires an admin to work as a complete and complex system. If there’s no admin, regular users will have a really hard time performing even the most basic actions. &lt;/p&gt;

&lt;p&gt;Custom LMS (Learning Management System) development solves all these problems perfectly. Developing your own products gives you all the freedom. Build them the way you want, with the interface you want. And it will work perfectly fine with some maintenance. &lt;/p&gt;

&lt;p&gt;And in the meantime, it offers a wide range of other opportunities for building a complex yet comprehensible product. Here’s a case example from our practice.&lt;/p&gt;

&lt;p&gt;When clients come to us with a request for an e-learning platform, they usually expect to see the following functionalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making lessons, tests&lt;/li&gt;
&lt;li&gt;Video conferencing with a digital whiteboard and shared document editing&lt;/li&gt;
&lt;li&gt;Video recording&lt;/li&gt;
&lt;li&gt;Classes booking&lt;/li&gt;
&lt;li&gt;Homework assignments that are not solely tests&lt;/li&gt;
&lt;li&gt;Publishing completed homework assignments (in .pdf, .doc(x), link, text)&lt;/li&gt;
&lt;li&gt;Media library: uploading presentation, pictures of the manual pages, notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moodle can do most of them, but with a number of limitations. &lt;/p&gt;

&lt;p&gt;One of our clients came to us with a request for a video conferencing with a whiteboard. There’s a Moodle plugin for that — &lt;a href="https://moodle.org/plugins/mod_bigbluebuttonbn"&gt;BigBlueButton&lt;/a&gt;. It has all the essential features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;having video calls for classes&lt;/li&gt;
&lt;li&gt;turning on/off the microphone&lt;/li&gt;
&lt;li&gt;screen recording&lt;/li&gt;
&lt;li&gt;controlling the conference as a host (block other users from joining the conference, etc.)&lt;/li&gt;
&lt;li&gt;screen sharing&lt;/li&gt;
&lt;li&gt;controlling video recordings&lt;/li&gt;
&lt;li&gt;whiteboards&lt;/li&gt;
&lt;li&gt;chat with emojis&lt;/li&gt;
&lt;li&gt;custom welcome messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To deploy all these features, it’ll take approximately 2 hours. If you also save some time for researching certain functionalities and plugins, you can extend the timespend to 8 hours. &lt;/p&gt;

&lt;p&gt;If you go for the custom development, it will take about 160 hours to develop the video chat, and 300 more hours for the whiteboard. &lt;/p&gt;

&lt;h2&gt;
  
  
  But where do these 452 extra hours take you?
&lt;/h2&gt;

&lt;p&gt;Basically it’s all about agileness. Moodle does have customization opportunities for colors, icons, etc. But when you need an whitelabel solution made specifically for you, like &lt;a href="https://forasoft.com/project/braincert"&gt;what we did on BrainCert&lt;/a&gt;, custom development guarantees the results in the estimated time. With Moodle you never know how much time it will take to find the way to customize a feature the way you need it and if you even get there at all. That is due to lack of support. &lt;/p&gt;

&lt;p&gt;With all of that said, the answer to the “Moodle of custom development for your LMS-product” is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If a platform is for internal use, doesn’t require any special features, and you’re on a low budget, then Moodle it is. But if you plan to monetize, promote, and attract many users to it, custom development is the right solution.&lt;/strong&gt; &lt;/p&gt;

</description>
      <category>elearning</category>
    </item>
    <item>
      <title>What Are Non-Functional Requirements And Why You Need Them? With Examples</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Fri, 07 Oct 2022 22:04:48 +0000</pubDate>
      <link>https://forem.com/forasoft/what-are-non-functional-requirements-and-why-you-need-them-with-examples-4lgi</link>
      <guid>https://forem.com/forasoft/what-are-non-functional-requirements-and-why-you-need-them-with-examples-4lgi</guid>
      <description>&lt;p&gt;Posted by Analytics T.&lt;/p&gt;

&lt;p&gt;Cool cat wearing sunglasses with the "NFR" text on each eye&lt;br&gt;
There’re essentials you have to think through before you’re to develop a product if you want it to work as you expect it to or even better. These are, as we explained in our &lt;a href="https://forasoft.com/blog/article/what-is-done-during-analytical-stage-of-software-development-1066"&gt;previous article&lt;/a&gt;, 2 types of requirements: functional and non-functional. From this article, you will learn what non-functional requirements are, and why they are as important as technical ones.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Non-Functional Requirement?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A non-functional requirement&lt;/strong&gt;, or NFR, is a requirement for the  system as a whole. It doesn’t describe user actions, system behavior, or interface. Instead, it determines WHERE the product  should be used and HOW we better design it from a technical perspective. Often NFRs are referred to as &lt;strong&gt;technical user stories&lt;/strong&gt; or &lt;strong&gt;software quality requirements&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is what the NFR list for a product may look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bUTgYFXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kqi0hiutiy4dyhfn4hc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bUTgYFXr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kqi0hiutiy4dyhfn4hc.png" alt="" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iQC_q01S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2jieboq6pb0164ikalv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iQC_q01S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j2jieboq6pb0164ikalv.png" alt="" width="880" height="495"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1-iTlFDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qcgmcn68tp6kfpmzgtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1-iTlFDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qcgmcn68tp6kfpmzgtl.png" alt="Example of a NFR-list for a video streaming platform or a video chat" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let’s dive deeper into the types of non-functional requirements to better understand why you even need to describe them in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements to for WHERE the system should work
&lt;/h2&gt;

&lt;p&gt;There are systems we expect to work everywhere: on any device, any platform, from any place. This is their technical requirement. For example, Facebook or YouTube. But they weren’t like that in the beginning. Making the system work flawlessly around the world on any device is pretty difficult and expensive. An &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263"&gt;MVP&lt;/a&gt; doesn’t need this to test their hypothesis and get the first users. That’s why we always ask our clients &lt;a href="https://forasoft.com/blog/article/why-active-app-users-are-important-1056"&gt;how many active users&lt;/a&gt; they plan to have in a few months and where they are located. This brings a lot of benefits: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;fits the initial system scale to the expected load — avoiding unnecessary scaling saves money;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;saves funds for not having to maintain the load that is not expected in the near future.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, when you ask yourself “Where should my system work?” and then answer your own question — this is how you articulate the non-functional requirements for localization (early adopter countries) and scalability (concurrent users, storage capacity).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: A Texas factory owner wants to develop a video surveillance system that can meet specific needs of the factory. NFRs to it will be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Localization: USA, language — American English&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability: 1 factory, 10 security officers, up to 100 simultaneous cameras.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most likely, this system will never have to experience the Black Friday test in Europe. However, if this is suddenly required (for example, the business grows in an unforeseen way), the factory owner will have to scale it up. &lt;/p&gt;

&lt;p&gt;However, it’s a big game changer if we consider the potential of scaling from the very beginning, it saves a lot of money.&lt;/p&gt;

&lt;p&gt;Some non-functional requirements don’t even require additional timespend. It takes the whole development some time to build a functional user story and features within. A technical user story, for instance, simply comments on the date and time formats for the specified use location.&lt;/p&gt;

&lt;p&gt;Technical user stories also determine the browser and device support. You might’ve seen a note like &lt;em&gt;“For the best experience, use the latest version of Chrome”&lt;/em&gt;? It indicates that the developers tested the platform, obviously, on the latest version of Chrome. It may work in other versions and browsers, but the software provider themselves don’t know how exactly — they haven’t tested it. Usually this is how companies save money on testing things and features not or least used by potential users. It’s a rather simple rule: you can grow a product and add new cool features to it only when the main functionality is working perfectly. &lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements for HOW the system should work
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Effective performance&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How to build it so that it works well? What does “well” even mean?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;: Let’s take the same video surveillance system. If we want it to work well, then the &lt;a href="https://forasoft.com/blog/article/how-video-as-technology-works-1004"&gt;video&lt;/a&gt; quality should be high (say, Full HD). But at the same time, we want to &lt;a href="https://forasoft.com/blog/article/how-to-estimate-the-server-cost-for-a-video-platform-249"&gt;optimize server costs&lt;/a&gt; so that the client doesn’t overpay. Most likely, Full HD is useless at night or when nothing happens in the picture. Then we lower the quality and boost it automatically when cameras detect motion. Or maybe leave the decision up to the user? They could set, for example, the main camera to 720p and the others to 480p. &lt;/p&gt;

&lt;p&gt;Depending on the specifics of the business, non-functional requirements for video quality can vary and must necessarily be specified in writing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Another side of “how well” is “how safe”. The system may collect or transmit sensitive (in terms of security, safety, or privacy) data. Not meeting relevant requirements can cause its owner major legal problems. In 2022 covering damage from data leaking may cost a company up to $4,35 million, according to the &lt;a href="https://www.ibm.com/security/data-breach"&gt;IBM data breach report&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Examples of security requirements: *&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The users of the platform should be over 18 y.o.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The payment processing gateway must be PCI DSS compliant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;1-1 calls should be HIPPA compliant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User profiles and data storage should be GDPR compliant.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Speed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Non-functional requirements also answer the “how fast” question, in case the speed is critical. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The results must load within 3 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Integrations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Last but not least, technical user stories define the necessary integrations into functional user stories, in case we don’t develop custom solutions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If the user needs to pay, the NFR specifies the payment method (e.g. Stripe, PayPal, in-app purchases, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user should receive a system email, the NFR says what system will perform it (e.g. MailChimp, Sendinblue, Mailgun).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user wants to watch a video, NFR determines the player.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the user needs to call, NFT names the video conferencing system to integrate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the client needs to analyze performance, NFT specifies the requirement for Google Analytics integration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on, so on, so on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s summarize
&lt;/h2&gt;

&lt;p&gt;To write complete non-functional requirements that can ensure the quality of the system, the analyst better discuss with the client and list the following possible attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Localization and Language / Multi-language support,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Date and Time formats, Timezone, Currency,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Current scale and potential Scalability,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Browser support,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Operating System / Device compatibility,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quality / Size / Format constraints,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security / Safety / Privacy concerns,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speed (Performance), Responsiveness, Reliability,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Third-party integrations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Functional and non-functional requirements go hand in hand when planning a system. While the first bring more value to the end user, the second explains where and how the product delivers that value. While describing non-functional requirements is crucial for building an &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263"&gt;MVP&lt;/a&gt;, it goes fil-rouge throughout the entire product life cycle.&lt;/p&gt;

</description>
      <category>analytics</category>
      <category>mvp</category>
      <category>requirements</category>
      <category>analyst</category>
    </item>
    <item>
      <title>What Hosting Provider Suits You: AWS vs DigitalOcean vs Hetzner [2022]</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Sun, 25 Sep 2022 15:09:07 +0000</pubDate>
      <link>https://forem.com/forasoft/what-hosting-provider-suits-you-aws-vs-digitalocean-vs-hetzner-2022-4b8j</link>
      <guid>https://forem.com/forasoft/what-hosting-provider-suits-you-aws-vs-digitalocean-vs-hetzner-2022-4b8j</guid>
      <description>&lt;p&gt;Out of dozens cloud hosting providers in Fora Soft we usually consider and build &lt;a href="https://forasoft.com/projects/all"&gt;our projects&lt;/a&gt; on three: AWS, Digital Ocean, and Hetzner. None of them is universal so in this article we’ll dive deeper into what specific needs and requirements each can cover.&lt;/p&gt;

&lt;p&gt;To know the cost of any of the servers listed for your project, use our &lt;a href="https://forasoft.com/calculator"&gt;Server cost calculator&lt;/a&gt;. It considers how many streamers and viewers you anticipate, and what quality your streaming service requires.&lt;/p&gt;

&lt;p&gt;But first…&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a cloud service and a cloud service provider (CSP)?
&lt;/h2&gt;

&lt;p&gt;We describe cloud service as any kind of infrastructure that a third-party provider hosts and makes available to users through the internet. Basically cloud services make the process of data delivery from a user’s device to the processing systems easier. &lt;/p&gt;

&lt;p&gt;All it takes for a cloud service to work is software and hardware. Literally like any other IT thing. What makes it different is that a device, connection to the network, and an OS is enough to access cloud services. &lt;/p&gt;

&lt;p&gt;Cloud service providers use their own data centers, physically located processing systems we already mentioned, and host platform services for customer organizations. Now in detail about 3 of them we use.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS (Amazon Web Services)
&lt;/h2&gt;

&lt;p&gt;AWS is the world’s most broadly adopted cloud platform with over 200 fully featured services from data centers globally. Basically a market leader. It serves 245 countries, has 27 already existing and 7 servers coming soon, all around the globe, on all continents.&lt;/p&gt;

&lt;p&gt;It’s safe to say they offer the broadest set of technical opportunities. Among their clients are fast-growing startups, largest enterprises, and leading government agencies. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does AWS make a great solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AWS is highly autonomous in its scalability. That means, the system ongoingly monitors changes in the system it hosts, detects the exact moment when it requires scalability and ensures that automatically. &lt;/p&gt;

&lt;p&gt;That results in a smaller chance of system crashing, better performance, and smoother user experience. &lt;/p&gt;

&lt;p&gt;Also what they have to show off is a plethora of IaaS’s (Infrastructure-as-a-Service) and PaaS’s (Platform-as-a-Service). These are ready-made solutions on a pay-as-you go basis. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xono7XQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rq5r6e0ocpbwpc4nzay.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xono7XQp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6rq5r6e0ocpbwpc4nzay.gif" alt="AWS tools" width="682" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But&lt;/strong&gt; obviously, such a smart and complex solution costs money. The AWS cost is the highest out of 3 providers we cover in this article. To not waste a pretty penny, it’s better to think twice if your product really needs that kind of scalability opportunities. One of the ways to figure it out is to ask yourself &lt;a href="https://forasoft.com/blog/article/why-active-app-users-are-important-1056"&gt;how many users you expect&lt;/a&gt; in the first few months. &lt;/p&gt;

&lt;p&gt;In a nutshell, AWS is a great solution if your company is large and you anticipate a lot of users at once, or if you need more complex, yet ready-made solutions. &lt;/p&gt;

&lt;h2&gt;
  
  
  DigitalOcean
&lt;/h2&gt;

&lt;p&gt;DigitalOcean is another American solution with 14 data centers in total in Asia, Europe, and North America. Their positioning states 3 main principles: keeping it simple, at affordable price, yet high-quality. And they live by that, mostly focusing on developers’ needs. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does DigitalOcean make great solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Their pricing is one of the most affordable among other providers in general. Still, they show brilliant results in terms of performance. Their network speed is 1Gbps and the start-up time is only 55 seconds. &lt;/p&gt;

&lt;p&gt;As for keeping it simple, DigitalOcean products have neat user-friendly interfaces with one-click deployments. &lt;/p&gt;

&lt;p&gt;The downside of DigitalOcean is a not-so-big choice of functionalities and instruments. At least, compared to AWS. That means, in case there’s no suitable tool for your project’s specific requirements, you’ll have to develop your own. &lt;/p&gt;

&lt;p&gt;But after all, the DigitalOcean server cost is almost 7 times less. &lt;/p&gt;

&lt;p&gt;Long story short, DigitalOcean is a great pick if it’s your first release or an &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263"&gt;MVP&lt;/a&gt; and you’re looking for a cheap yet reliable cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hetzner Cloud
&lt;/h2&gt;

&lt;p&gt;Hetzner Cloud is a German provider with data centers in 4 locations: in Bavaria and Saxony lands in German, in Helsinki, and in the state of Virginia, USA. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why does Hetzner Cloud make a great solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hetzner Cloud has all the essentials required to start an app, yet they keep prices low and affordable.  &lt;/p&gt;

&lt;p&gt;So basically Hetzner, in terms of pricing and effectiveness, is a European alternative to DigitalOcean. As a bonus, it’s not that well known yet, so it’s even cheaper. Perfect for first releases and small startups. &lt;/p&gt;

&lt;p&gt;Since Hetzner locates its data centers mostly in Europe, you might want to consider building on it if you know for sure 90% of your users will be browsing from Europe. Otherwise you can end up losing in speed and overall user experience.&lt;/p&gt;

&lt;p&gt;Another con is lack of agileness in choosing servers and tools, same as it is with Digital Ocean. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;To sum it all up, here’re the essentials to consider when picking a CSP out of 3 listed:&lt;br&gt;
How many users do you expect to use your product at once?&lt;br&gt;
How fast do you plan to grow?&lt;br&gt;
Where are your users browsing from?&lt;br&gt;
And now a quick summary on what each CSP:&lt;/p&gt;

&lt;p&gt;You might want to build your product on &lt;strong&gt;AWS&lt;/strong&gt; if you have to serve hundreds of thousands of people at once, have a big enterprise, or plan to grow fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DigitalOcean&lt;/strong&gt; is a great pick for you if you’re looking for a low cost, yet reliable media server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hetzner Cloud&lt;/strong&gt; will make it even cheaper, yet more suitable for Europe (but not limited by it). &lt;/p&gt;

&lt;p&gt;These are the main providers we work with, but if you have your own favorites or non of them seems to be a match, we can turn to any other CSP.&lt;/p&gt;

&lt;p&gt;To calculate your monthly server costs, use our &lt;a href="https://forasoft.com/calculator"&gt;Server cost calculator&lt;/a&gt;. And to know the overall price of a project, contact us at &lt;a href="mailto:info@fora-soft.com"&gt;info@fora-soft.com&lt;/a&gt; or our Head of Sales Vadim on Skype: vadim_prushchik&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloudpovider</category>
      <category>digitalocean</category>
      <category>cloud</category>
    </item>
    <item>
      <title>What Should Come After The 1st MVP Release For It to Be a Success?</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Mon, 12 Sep 2022 15:51:25 +0000</pubDate>
      <link>https://forem.com/forasoft/what-should-come-after-the-1st-mvp-release-for-it-to-be-a-success-17cc</link>
      <guid>https://forem.com/forasoft/what-should-come-after-the-1st-mvp-release-for-it-to-be-a-success-17cc</guid>
      <description>&lt;p&gt;Posted by Maria A.&lt;/p&gt;

&lt;p&gt;In Fora Soft when we release a product for the first time, it's already an &lt;a href="https://forasoft.com/blog/article/what-is-done-during-analytical-stage-of-software-development-1066"&gt;MLP (Minimum lovable product)&lt;/a&gt;. But usually the first milestone in product development is &lt;a href="https://forasoft.com/blog/article/what-is-mvp-263"&gt;MVP (Minimum viable product)&lt;/a&gt; launch. However, it's not a point to stop. But what to do next? What comes after MVP release and how do you know the product is ready? The answers are in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gather feedback from your users
&lt;/h2&gt;

&lt;p&gt;If you want your MVP to be a perfect product-market fit, it's a good idea to make sure your clients understand what the product is about and how they should interact with it before promoting the platform. Otherwise there's a chance you spend a pretty penny on marketing and get no result.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sign up for startup websites
&lt;/h3&gt;

&lt;p&gt;Like these:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.producthunt.com/"&gt;Product Hunt&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.indiehackers.com/"&gt;Indiehackers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://betalist.com/"&gt;Betalist&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The scheme here is quite easy yet effective:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sign up and set up the profile page.&lt;br&gt;
For example: &lt;a href="https://www.producthunt.com/posts/tapereal"&gt;https://www.producthunt.com/posts/tapereal&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.indiehackers.com/product/tapereal-com"&gt;https://www.indiehackers.com/product/tapereal-com&lt;/a&gt;&lt;br&gt;
&lt;a href="https://betalist.com/startups/superday"&gt;https://betalist.com/startups/superday&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Post updates, reply to questions other users ask and chat with them&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your profit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;feedback from real users = the "Do they need the product?" hypothesis testing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;badge on your website = trust level increase&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DKa5olWS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qhyndav1wuyxfen7vigl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DKa5olWS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qhyndav1wuyxfen7vigl.png" alt="Badge on a website" width="880" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the platform on users
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Determine your target audience&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;TA is a group of people that are most likely interested in your product. They share some needs and wants or have similar ones.&lt;br&gt;
For instance, TA for an LMS-system is students and teachers that take and give lessons online.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test your product with focus groups&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gather up a group of 10 people
They shall be as close to how you describe your TA as possible. It's better if they're strangers to you - friends and family might not be objective.&lt;/li&gt;
&lt;li&gt;Decide what exactly you want to test
For instance, your goal is to test how intuitively students interact with the platform.
Describe the scheme: "Download the app, sign up, make basic actions (sign up for a class, attach a file with a completed assignment)".
Plan the result: "9 users will register, 5 will sign up for a class, 3 will attach their files".&lt;/li&gt;
&lt;li&gt;Test the platform
We recommend watching the users as they interact with the product: face-to-face or on a video call. You'll notice some minor yet important details the user might've missed in a written report.&lt;/li&gt;
&lt;li&gt;Gather feedback
Note what users could and couldn't do or accomplish. What questions and issues have they faced? Were there lags or bugs they encountered? Did they like using the product, why? Would they recommend it to a friend? Would they use it themselves?&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Carry out a customer development interview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/document/d/1TZC3psp9IKgIr6SCQ7FP_kLryMMg-mpambrievFs4II/edit?usp=sharing"&gt;Customer development interview (Custdev)&lt;/a&gt; - a means to get data while in-depth interviewing TA. While carrying out a custdev you &lt;a href="https://docs.google.com/document/d/1IPuCGGtLT_2F5rmpkhZFM6009CJm2ihZDjwlqH2Nzds/edit#"&gt;discover current top-of-mind needs&lt;/a&gt;, preferred means of communication and content types. You'll need these for the promoting campaign later.&lt;br&gt;
&lt;em&gt;Tip: If you're on a low budget and can't afford a custdev, prepare the questions in advance and ask them while testing the product with the users. And if you've already made past-testing amendments, now it's a good idea to see if the amendments are good and efficient.&lt;/em&gt;&lt;br&gt;
Custdev aims at discovering how and where your TA gets information and what particular points for ads placement will be the most effective.&lt;/p&gt;

&lt;p&gt;There're some &lt;strong&gt;Rules&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gather up a group of 10 people. They shall be as close to how you describe your TA as possible. Again, it's better if they're strangers to you - friends and family might be not objective.&lt;/li&gt;
&lt;li&gt;Make a questionnaire. With the same questions for each of the respondents to prove the hypothesis.&lt;/li&gt;
&lt;li&gt;Ask open questions: how, what, why. Let the respondents share their experience in detail. Don't ask them for a particular solution. Just find out what the problem is and why solving it is important for the respondent.&lt;/li&gt;
&lt;li&gt;Ask follow up questions.&lt;/li&gt;
&lt;li&gt;Remain in the present. Ask them how they act right now (no woulda-shoulda-coulda and Past tenses). Focus on how they tend to act. And better not ask about the future or wishes. The respondent may subconsciously want to appear better than they are and respond accordingly, but it won't correlate with how they act in a real setting.&lt;/li&gt;
&lt;li&gt;Record the interview. You'll get a bigger load of data and will be able to come back to it anytime you need, the data mining will be more effective.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/document/d/1li-tVZ1E4qYKuDp0yi7orBDjckbjdEIs4aCi1GXDQdU/edit?usp=sharing"&gt;Questions you might want to ask&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Process the feedback
&lt;/h2&gt;

&lt;p&gt;Effective feedback processing and eliminating product flaws are two Atlases of successful products. If a user can't fulfill their needs and wants with a product, or the first-use experience is unpleasant, they won't waste their time on it anymore.&lt;/p&gt;

&lt;p&gt;How to process feedback correctly:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Discuss the feedback with the team&lt;/li&gt;
&lt;li&gt;Brainstorm on possible solutions and improves together&lt;/li&gt;
&lt;li&gt;Make up a to-do list for the next release. Use MoSCoW prioritization method(&lt;strong&gt;M&lt;/strong&gt;ust have, &lt;strong&gt;S&lt;/strong&gt;hould have, &lt;strong&gt;C&lt;/strong&gt;ould Have, &lt;strong&gt;W&lt;/strong&gt;on't have (this time)) to prioritize:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;1st Priority&lt;/strong&gt;: features that the product Must have. These are the essentials for the current development stage. If a product doesn't have them, it won't be successful. Basically, an MVP already has it. You can only improve them or add new ones if the custdev shows it's necessary.&lt;br&gt;
&lt;strong&gt;2nd Priority&lt;/strong&gt;: features that are important for the current stage but aren't that critical. A product Should have them in the next development sprint.&lt;br&gt;
&lt;strong&gt;3rd Priority&lt;/strong&gt;: features that could make a product better if there was additional development budget. It's what the product Could have at its best.&lt;br&gt;
&lt;strong&gt;4th Priority&lt;/strong&gt;: features that will definitely not be in the product, at least for the next 2 timeboxes. It's what it Won't have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We recommend focusing on the 1st and 2nd priorities as they suggest most needed improvements for the current period of time.&lt;/strong&gt; The 3rd and 4th ones are just possible enhancements. When improving the product, you may see it change dramatically so there won't be any need for the features of the 3rd and 4th priorities. So it's better not to waste your funds and your analysts team's time on that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make changes to the product
&lt;/h2&gt;

&lt;p&gt;Adapt your MVP to be better product-market fit with your clients. Develop and test 1st and 2nd priorities improves. Besides custom solutions, some common ones are have the same intentions: explain how to use the platform for newbiews and keep them engaged.&lt;/p&gt;

&lt;h3&gt;
  
  
  Onboarding
&lt;/h3&gt;

&lt;p&gt;Automated platform introduction to a user. The goal is to demonstrate what it is for, how to use it properly, and what the benefit is. It makes the user experience much smoother and leaves a good first impression.&lt;/p&gt;

&lt;h3&gt;
  
  
  Minor interface adjustments
&lt;/h3&gt;

&lt;p&gt;Product adaptation is a nice product enhancement strategy. It's a pretty common thing when a user can't find the target action button or doesn't get how to interact with certain functionalities. It's crucial to keep abreast, keep track of the feedback.&lt;/p&gt;

&lt;p&gt;This is why sometimes it's a good idea to test how comprehensible and intuitive the interface is to the user if there's no additional navigation. It's easy to assess. Let's say the user scenario suggests that the "Sign up for a class" action takes 3 steps. When testing the product you see that the user takes some workarounds and accomplishes it in 10 steps. Meaning something in the interface wasn't clear for them. This will help add new useful features and enhance existing UX and UI in the next product version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referral system
&lt;/h3&gt;

&lt;p&gt;It's a way for the platform to "collaborate" with the user by rewarding the referrer for attracting new users. Nothing motivates better than personal gain. Think of what would be enough of a motivation for one to stick to their friend asking for a favor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notifications
&lt;/h3&gt;

&lt;p&gt;One of the significant metrics of the app effectiveness is user engagement. How frequently they open the app, how much time they spend in it. Notifications will help with the first. Pique their interest with words and emojis only.&lt;/p&gt;

&lt;p&gt;Custom email newsletters will work for web apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Text update applying Tone of Voice
&lt;/h3&gt;

&lt;p&gt;If you use texts at the MVP stage (in pop-ups, welcome-screens, etc.) make them consistent in Tone of Voice. These are the rules by which the brand communicates with the users.&lt;/p&gt;

&lt;p&gt;Does your product target teens? Use more slang to be on the same wavelength. Is your TA mostly businessmen and entrepreneurs? Address the users more respectfully and make the communication concise, maybe even formal.&lt;/p&gt;

&lt;p&gt;Relevant ToV guarantees that users will perceive the information better, since they better understand how the product works.&lt;/p&gt;

&lt;p&gt;Moreover, if your brand speaks the same language as its TA, some sort of emotional connection and bond establishes between them, as if they were friends. That's a significant advantage over competition products.&lt;/p&gt;

&lt;h2&gt;
  
  
  Promote the platform
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pick the promotion channels and plan the works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Think of the concept&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Pick the promotion channels&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on the custdev data make a list of the most potentially effective sites for placing advertising messages.&lt;br&gt;
&lt;em&gt;For example, your clients are movie geeks that want to save money on online cinema subscriptions. From the interview we learnt that they visit platforms with vouchers and promo codes often. This is where we will place our ads.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Set up the channels in the single brand identity. Use the same logo and an informative profile background. Let your designer make an entire design system, select color solutions for visual content.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make your advertisement hypotheses (objectives) to test. Make them SMART&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;For example, Facebook users will download the app 100 times within 2 weeks.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculate the overall costs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use forecasting services for digital advertisements. When planning a campaign in Google ads, Facebook ads, Snapchat ads, TikTok ads, Twitter ads you'll see how many impressions &lt;em&gt;(how many unique users will see the ad&lt;/em&gt;) and clicks you'll get for your budget.&lt;br&gt;
Agree on promotional posts with authors/admins personally. Consider the fees and taxes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Plan content creation works: make briefs for copywriters, designers, photographers, etc.
###Create the content
Use the information you gained from custdev to determine the best content type for your TA. Write copies, record and edit the video, make pictures, and adjust them to your specific placement sites.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the campaign includes any social media marketing activity, make up a content-plan, a list of posts topics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launch a test campaign
&lt;/h3&gt;

&lt;p&gt;Commence promoting the product and testing hypotheses. We recommend launching a test campaign for 2 weeks - this must be enough. Keep track of the changes. If you see that one of the hypotheses doesn't prove itself and you don't get the anticipated result, amend the budget allocation, channels selection, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Launch the campaign in the most effective channels
&lt;/h3&gt;

&lt;p&gt;Draw the conclusions to the test campaign. Select the most effective ads placement sites. Plan the budget and the results based on the test campaign data. "With the $ X budget I'll get Y new users, N demo requests". Use this to better plan and calculate ROI of the project in the long-term perspective.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;Answering the question from this article intro - you know better when your product is ready. What we can say for sure is that there's always room for improvement in the post MVP phase. And once you have your MVP and have done all the necessary adjustments, you'll know the direction. To give you an idea, check out what we do next with our clients in &lt;a href="https://forasoft.com/blog/article/richard-from-community-hill-software-development-review-1178"&gt;CommunityHill&lt;/a&gt;, &lt;a href="https://forasoft.com/blog/article/vodeo-app-development-review-janson-media-915"&gt;Janson Media&lt;/a&gt;, and &lt;a href="https://forasoft.com/blog/article/appybee-software-development-review-764"&gt;AppyBee&lt;/a&gt; cases.&lt;/p&gt;

</description>
      <category>mvp</category>
      <category>marketing</category>
      <category>analytics</category>
    </item>
    <item>
      <title>How to Test WebRTC Stream Quality? Use StreamTest Extension [Free]</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Tue, 06 Sep 2022 07:22:28 +0000</pubDate>
      <link>https://forem.com/forasoft/how-to-test-webrtc-stream-quality-use-streamtest-extension-free-1fi5</link>
      <guid>https://forem.com/forasoft/how-to-test-webrtc-stream-quality-use-streamtest-extension-free-1fi5</guid>
      <description>&lt;p&gt;As someone specializing in video chat and video streaming services, our QAs (quality assurance angels) used to deal with the problem of how to test a live stream quality with a load of tools and apps, all different for each metrics. But now there’s this all-in-one solution — &lt;a href="https://chrome.google.com/webstore/detail/streamtest/apmgkjaoljlahcldcoekghdngcbceebf?hl=en"&gt;StreamTest&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It’s a Google Chrome Extension, a testing tool for WebRTC video chats like Google Meet, iMind, Whereby, and ProVideoMeeting. Not sure you’re on a WebRTC stream? Enable StreamTest and if you’re trying to test a non-WebRTC stream, the extension will respond with an error. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QGSKMilI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxh1imzp9f4gg6ksglg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QGSKMilI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxh1imzp9f4gg6ksglg5.png" alt="Non-WebRTC stream error" width="880" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It’ll give you a live status on 7 essential parameters with an insight on the connection and stream behavior. &lt;/p&gt;

&lt;p&gt;Quick note for non-tech folks:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you have no technical background and all of these indicators are just letters, figures, and colors to you or don’t want to analyze them yourself, just screenshot (Windows: Win + Shift + S; MacOS: Command + Shift + 3) the status you got immediately, download the report as a .csv file, and show both to your tech specialist.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We are already working on making the plugin accessible for you, so you could test your live streams easily, guys. So follow us on &lt;a href="https://linkedin.com/company/fora-soft-llc-"&gt;LinkedIn&lt;/a&gt; to stay turned.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1CIlPVOM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvg6x5vdbdl3sgo085i9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1CIlPVOM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvg6x5vdbdl3sgo085i9.png" alt="Video conference live status" width="880" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Frame rate&lt;/strong&gt; or just FPS. The higher the better. To calculate it the plugin measures the time between two frames and calculates the average for the last X frames.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Video and Audio delay&lt;/strong&gt;. Delay is never welcome, so the lower the better. Basically it’s a sum for jitterBufferDelay and average round trip time. Totals are relevant for the last 3*X seconds, where X is the time set in setInterval.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Packet loss&lt;/strong&gt;. The lower the better. It shows if any packets were lost on the way to the server, as a percentage. Calculated as (packetsLost stat / packetsSent stat) * 100%. &lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Resolution&lt;/strong&gt;. The higher the better. It mostly depends on the participant’s camera and the device you’re using to chat. &lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Freezes and stalls&lt;/strong&gt;. The lower this indicator is the better. It shows how much % of your call was wasted due to lags. Consider something as freeze if the comparison (!wasDocumentJustHidden &amp;amp;&amp;amp; dt &amp;gt; Math.max(dtTimestampsQueue.getAverage() * 3, dtTimestampsQueue.getAverage() + 0.150)) is true. In simple terms freeze happens if the time of the current frame is greater than the average time of frame existence multiplied by 3. And at the same time is greater than the average time of frame existence for at least 150ms. &lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Bitrate&lt;/strong&gt;. This indicator is responsible for how smooth the picture is, the higher the indicator the smoother the picture.&lt;/p&gt;

&lt;p&gt;– &lt;strong&gt;Video and Audio codec&lt;/strong&gt; — for a developer to know how the data is compressed.&lt;/p&gt;

&lt;p&gt;In the status you’ll also notice that the indicator measures are colored in Red, Yellow, or Green. Here’s what the colors mean:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n3I7Mulf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g494nl1vdcfq4m1t1ask.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n3I7Mulf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g494nl1vdcfq4m1t1ask.png" alt="StreamTest live status colors meaning" width="880" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Besides the data we described previously, there’re also SDP offer, answer, iceConnectionState, iceGatheringState, and WebRTC Stats info in the downloadable .csv report. It will give the bigger picture of the connection and the stream behavior. &lt;/p&gt;

&lt;p&gt;StreamTest starts collecting data once you enable it. To do it, click your right mouse button on the other participant’s stream and tap “Test stream” in the context menu. It will stop collecting the data once you close the extension / start testing another stream / go to the extension main screen. &lt;/p&gt;

&lt;p&gt;To test live streams, download this WebRTC tester for your Chrome from the official store &lt;a href="https://chrome.google.com/webstore/detail/streamtest/apmgkjaoljlahcldcoekghdngcbceebf?hl=en"&gt;here&lt;/a&gt;. For free. &lt;/p&gt;

</description>
      <category>webrtc</category>
      <category>qa</category>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to Implement Delayed Messages with RabbitMQ? Code Examples</title>
      <dc:creator>Fora Soft</dc:creator>
      <pubDate>Tue, 30 Aug 2022 09:57:00 +0000</pubDate>
      <link>https://forem.com/forasoft/how-to-implement-delayed-messages-with-rabbitmq-code-examples-3ao0</link>
      <guid>https://forem.com/forasoft/how-to-implement-delayed-messages-with-rabbitmq-code-examples-3ao0</guid>
      <description>&lt;p&gt;Sometimes you need to implement scheduled or repeating actions into your app. For example, sending a push-notification in 10 minutes or clearing a temporary folder every day.&lt;br&gt;
To do this, you can use cron-tasks, that run scripts on your server automatically, or node-schedule package (a task-planning library for Node.js).&lt;br&gt;
But with both these solutions there's a scaling problem:&lt;br&gt;
There're several servers so it might be unclear on which one to run the task&lt;br&gt;
The selected server might crash&lt;br&gt;
The node might get deleted for freed up resources&lt;/p&gt;

&lt;p&gt;One of possible solutions here is RabbitMQ, a message broker. Check out the overall delayed messages implementation scheme in this example on GitHub. And here's what it's like in detail, step by step:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Create 2 exchangers: regular and delayed one.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const HELLO_EXCHANGE = Object.freeze({
    name: 'hello',
    type: 'direct',
    options: {
        durable: true,
    },
    queues: {},
});
export const HELLO_DELAYED_EXCHANGE = Object.freeze({
    name: 'helloDelayed',
    type: 'direct',
    options: {
        durable: true,
    },
    queues: {},
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. In each of the exchangers create queues with the same binding type but different names.&lt;/strong&gt;&lt;br&gt;
For HELLO_EXCHANGE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queues: {
        WORLD: {
            name: 'hello.world', // subscribe to this queue
            binding: 'hello.world',
            options: {
                durable: true,
        },
    },
},
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For HELLO_DELAYED_EXCHANGE:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queues: {
      WORLD: {
            name: 'helloDelayed.world',
            binding: 'hello.world',
            options: {
                durable: true,
                queueMode: 'lazy', // set the message to remain in the hard memory
        },
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the delayed-exchanger's queue, set the x-dead-letter-exchange argument with the regular queue's name. The argument tells the RabbitMQ broker to transfer the message to this exchanger if it's not processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arguments: {
                'x-dead-letter-exchange': HELLO_EXCHANGE.name, // set the queue to transfer the message to once it's dead
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Publish the message to the delayed-exchanger's queue with the expiration period&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/hello/publisher.ts
export const publishHelloDelayedWorld = createPublisher({
    exchangeName: exchangeNameDelayed,
    queue: WORLD_DELAYED,
    expirationInMs: 30000, //set when the message dies (in 30s)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the delayed message expires, it will go to the regular exchanger's queue.&lt;br&gt;
Now you only have to set a consumer for the regular exchanger's queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () =&amp;gt; Promise.all([
    createConsumer(
        {
            queueName: HELLO_EXCHANGE.queues.WORLD.name,
            prefetch: 50,
            log: true,
        },
        controller.consumeHelloWorld,
    ),
]);
// services/base-service/src/broker/hello/controller.ts
export const consumeHelloWorld: IBrokerHandler = async ({ payload }) =&amp;gt; {
    const result = await world({ name: payload.name });
    logger.info(result.message);
    // await publishHelloDelayedWorld({ name: payload.name }); // if you need to process the message again
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Profit!&lt;br&gt;
If you need to run the action periodically, publish the message to the delayed exchanger again at the end of the consumer section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// await publishHelloDelayedWorld({ name: payload.name });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: RabbitMQ operates on FIFO (first in, first out) - it processes commands in the same order they were set. So if you publish a delayed message with 1 day expiration and a message with 1 minute expiration in the same queue, it will process the second message after the first one, and the target action for the second message will happen a minute after the first.&lt;br&gt;
Eventually, this is what you get:&lt;br&gt;
&lt;strong&gt;1. Create the exchangers and queues&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/const/exchanges.ts
export const HELLO_EXCHANGE = Object.freeze({
    name: 'hello',
    type: 'direct',
    options: {
        durable: true,
    },
    queues: {
        WORLD: {
            name: 'hello.world', // subscribe to this queue
            binding: 'hello.world',
            options: {
            durable: true,
            },
        },
    },
});
export const HELLO_DELAYED_EXCHANGE = Object.freeze({
    name: 'helloDelayed',
    type: 'direct',
    options: {
        durable: true,
        queueMode: 'lazy', // specify that the hard memory must store this message
},
queues: {
    WORLD: {
        name: 'helloDelayed.world',
        binding: 'hello.world',
        options: {
            durable: true,
            queueMode: 'lazy', // specify that the hard memory must store this message                arguments: {
                'x-dead-letter-exchange': HELLO_EXCHANGE.name, // specify the queue to which the message must relocate after its death
                },
            },
        },
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Add the publisher that will send the message to the delayed queue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/hello/publisher.ts
export const publishHelloDelayedWorld = createPublisher({
    exchangeName: exchangeNameDelayed,
    queue: WORLD_DELAYED, 
    expirationInMs: 30000, // set when the message dies (in 30s)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3. Add the consumer for the regular exchanger's queue&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () =&amp;gt; Promise.all([
    createConsumer(
        {
            queueName: HELLO_EXCHANGE.queues.WORLD.name,
            prefetch: 50,
            log: true,
        },
        controller.consumeHelloWorld,
    ),
]);
// services/base-service/src/broker/hello/controller.ts
export const consumeHelloWorld: IBrokerHandler = async ({ payload }) =&amp;gt; {
    const result = await world({ name: payload.name });
    logger.info(result.message);
    // await publishHelloDelayedWorld({ name: payload.name }); // if you need to process the message again
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4. Profit!&lt;/strong&gt;&lt;br&gt;
There's also a &lt;a href="https://github.com/rabbitmq/rabbitmq-delayed-message-exchange"&gt;plugin&lt;/a&gt; that does this work for you and makes the implementation easier. You only create one exchanger, one queue, one publisher, and one consumer.&lt;br&gt;
When publishing, the plugin will process the delayed message and, once it's expired, will transfer the message to the right queue. All on its own.&lt;br&gt;
With this plugin the scheduled messages are processed in the order of the expiration time. That means, if you publish a message with a 1-day delay and then a message with 1-minute delay, the second one will be processed before the first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/const/exchanges.ts
export const HELLO_PLUGIN_DELAYED_EXCHANGE = Object.freeze({
   name: 'helloPluginDelayed',
   type: 'x-delayed-message', // specify the delayed queue
   options: {
       durable: true,
        arguments: {
          'x-delayed-type': 'direct', // set the recipient      
        },
    },
    queues: {
        WORLD_PLUGIN_DELAYED: {
            name: 'helloPluginDelayed.world', // subscribe to the queue
            binding: 'helloPluginDelayed.world',
            options: {
                durable: true,
            },
        },
    },
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add publisher that sends the messages to the delayed queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const publishHelloPluginDelayedWorld = createPublisher({
    exchangeName: exchangeNamePluginDelayed,
    queue: WORLD_PLUGIN_DELAYED,
    delayInMs: 60000,  // specify when the message should die (60s)
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add consumer to the queue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () =&amp;gt; Promise.all([
    createConsumer(
        {
            queueName: HELLO_PLUGIN_DELAYED_EXCHANGE.queues.WORLD_PLUGIN_DELAYED.name,
            prefetch: 50,
            log: true,
        },
        controller.consumeHelloWorld,
    ),
]);
// services/base-service/src/broker/hello/controller.ts
export const consumeHelloWorld: IBrokerHandler = async ({ payload }) =&amp;gt; {
    const result = await world({ name: payload.name });
    logger.info(result.message);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aaand - you're done!&lt;/p&gt;

&lt;p&gt;We regularly use RabbitMQ in our projects. For instance, check out its use case in &lt;a href="https://forasoft.com/project/janson-media-internet-tv"&gt;Janson Media internet TV&lt;/a&gt; portfolio. It's a movie renting service, but make it digital.&lt;/p&gt;

&lt;p&gt;Here we used RabbitMQ delayed messages for the app's 3 essential features: sending emails and SMS-messages to notify users that, for example, their lease period is almost over; sending messages about completed payments to the socket and sending a notification to the user; sending uploaded videos for further processing.&lt;/p&gt;

&lt;p&gt;Hopefully, implementing delayed messages won't be like falling down the rabbit hole for you anymore (if it ever was) 🙂&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>codenewbie</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
