Categories
Uncategorized

Top 6 Online and Offline Investment Sources for Your Software

a mobile phone with a coin getting into it

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?

This article will answer your questions.

There are three types of investment seekers

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.

You have a general idea of what the product is going to be but you haven’t worked through the details

It all starts with an idea. If you have it already but are still not sure about the details, look into Angel Investment.

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. 

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. 

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. 

To find an angel you don’t necessarily need an old rich aunt or Jeff Bezos as your friend 

Try these

  • Angellist — 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.
  • Angel Investment Network — kind of a marketplace to connect startups with investors.
  • Social media — tell about your ideas on your Twitter or LinkedIn and ask your contacts to share the info. Six degrees of separation and the power of weak ties are real!

Another category is:

You have a detailed idea description and solid understanding of how it will work

For when you:

  • know exactly what you and your business need
  • you know you will grow fast and investors will see it too

Go venture!

Venture capitalists 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. 

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. 

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 extraordinary growth potential. 

Here is what you need to do to win investment from a VC:

1. 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 CB Insights — it’s a highly-regarded resource that offers data on active VC firms and associated industries.

2. 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. 

3. 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 Crunchbase.

4. Prepare your pitch presentation. You need to literally sell your idea to the investors. Here’s what you should cover.

  • 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.

    You should also research into your TA. The more client-oriented you are, the better. Try out field study for that. 
  • Problem, solution, and product image. Use prototypes, designs, or demo.
  • Technology / Innovation
    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.
  • Monetization model
    This is how you plan to make money with your product and how realistic it is to make money off the product.
  • Team and implementation
    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.
  • How realistic it is to enter the market
    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.

You need a mentor, a network, and support in building your business

No matter what stage you are at, business incubators might be a good solution for you.

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

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. 

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.

To find an incubator 

Try the IncubatorList

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.

There’re investment seeking strategies that work well for all three types

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

1. Friends & Family

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.

Mail chimp and Github bootstrapped themselves. See who else.

2. Crowdfunding

Make a million stranges who believe in your idea donate a dollar. How to do that:

  1. Create a campaign
  2. Make the content to engage people
  3. Set up and launch the campaign
  4. Promote campaign: e.g. on social media

Reward-based crowdfunding

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. 

Where to crowdfund reward-based:

  1. Kickstarter 

Crowdfunding platform for creative community. You might want to place your project campaign in the Technology category. There are subcategories for apps, software, and web services

Kickstarter Fees calculator
Kick starter Fees calculator

The mechanic is All or nothing: 

  • set your objective you’re seeking to crowdfund (try their template for objective estimation in .xls). If you don’t get it, all the money goes back to the backers and you get nothing.
  • 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. 
  • 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.

Your or your business address must be located in one of the listed countries and have a bank account that meets the platform requirements. And make sure you project is none of this

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 here.

For example

kick starter project set up page with the list of categories
Kickstarter project set up page

Why is it a good idea to crowdfund on Kickstarter?

  • Can start promotion before everything’s ready by creating Pre-launch page 

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.

  • Connect Google Analytics to the campaign.

That means you can advertise on YouTube, Google search, or the affiliated website with Google ads.

  1. Indiegogo 

Your project might fit into Tech&Innovation category with Education, Health & Fitness, Productivity 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: Fluent Forever App: THINK In Any New Language

Check out the legal address and bank account requirements. 

How much can you raise?

Indiegogo offers two funding types: Flexible Funding (keep what you raise) and Fixed Funding (all-or-nothing). Learn about the differences and the pricing for each.

  1. Kisskissbankbank

It’s a French crowdfunding platform where you can finance your project with regular support of your community. Choose a monthly or quarterly recurrence and create your own subscription formulas, offer exclusive content to your contributors and finance the sustainability of your project over the long term!

Equity crowdfunding

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. 

Where to equity crowdfund:

Depending on where you and your business are located, you might want to try one of these platforms:

Worldwide

Canada

USA 

UK

Europe

Middle East

3. Initial coin offering

ICO is a form of investment where funds are raised with cryptocurrency venture. How to get into ICO:

  1. 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.
  2. Publish it on any cryptocurrency stock market (e.g. Binance) and promote it.
  3. Get crypto donations (mostly in Ethereum) from backers. They’ll get project’s tokens in return.
  4. Once your project succeeds the backers can sell their tokens and profit, so in case of your success it’s a win-win situation.

Here’s top 10 most recommended platforms for ICO

Bad news: ICO involves a lot of risk taking. Good news: risks are mostly for the backers. 

Listing an ICO is not free, though. Rough estimates are in the range of $40,000 to $200,000.  

Conclusion

You might be seeking investment on different stages of your project development. The first one here can be building an MVP. Learn how to save money on that from our article.

And if you already have one and are seeking further stages funding, here’s what you should probably allocate budget to before you spend a penny on the actual development. 

Categories
Uncategorized

Moodle VS Custom Development: What’s Best For Your E-learning Product

Colorful picture with devices and e-learning platforms' interface in them

You might feel on the crossroad when planning out your e-learning platform. “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 your questions. 

Our clients ask us about Moodle so let’s use it as an example. 

What is Moodle?

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.

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 free tool with lots of additional plugins that help you install any software your users might need. 

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:

a table comparing two solutions
Moodle and custom development comparison table

Now in detail.

How do I know Moodle is enough for me?

There are cases when you can save up a lot of money by just building your courses in Moodle. It is when:

  • You need the platform for internal use
  • Custom UI design adapted to your branding is not a priority
  • You’re on a low budget

Moodle truly does have some benefits.

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 GNU (General Public License).

Secondly, Moodle works on most servers that support PHP. Users can install, use, and update it on any device.

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.  

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 them on a forum. 

What issues you are probably going to have 

  1. Long time to solve tech issues
    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 makes problem solving quite complicated.
  2. Difficulties in using plugins
    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.
  3. Need for an admin

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. 

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. 

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.

When clients come to us with a request for an e-learning platform, they usually expect to see the following functionalities:

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

Moodle can do most of them, but with a number of limitations. 

One of our clients came to us with a request for a video conferencing with a whiteboard. There’s a Moodle plugin for that — BigBlueButton. It has all the essential features:

  • video calling for classes
  • turning on/off the microphone
  • screen recording
  • controlling the conference as a host (block other users from joining the conference, etc.)
  • screen sharing
  • controlling video recordings
  • whiteboards
  • chat with emojis
  • custom welcome messages

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 time spent to 8 hours. 

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. 

But where do these 452 extra hours take you?

Basically it’s all about agileness. Moodle does have customization opportunities for colors, icons, etc. But when you need a white label solution made specifically for you, like what we did on BrainCert, 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. 

With all of that said, the answer to the “Moodle of custom development for your LMS-product” is:

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. 

Either way we’ll be happy to help you build a successful product, So feel free to contact us and discuss your ideas. We’ll come up with the solution and time + cost estimations shortly.

Categories
Uncategorized

What Are Non-Functional Requirements And Why You Need Them? With Examples

Cool cat wearing sunglasses with the "NFR" text on each eye

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 previous article, 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.

What is a Non-Functional Requirement?

A non-functional requirement, 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 technical user stories or software quality requirements.

This is what the NFR list for a product may look like:

A table with different non-functional requirements and their specifications
A table with different non-functional requirements and their specifications
A table with different non-functional requirements and their specifications
Example of a NFR-list for a video streaming platform or a video chat

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.

Requirements to for WHERE the system should work

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 MVP doesn’t need this to test their hypothesis and get the first users. That’s why we always ask our clients how many active users they plan to have in a few months and where they are located. This brings a lot of benefits: 

  • fits the initial system scale to the expected load — avoiding unnecessary scaling saves money;
  • saves funds for not having to maintain the load that is not expected in the near future.

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).

Example: A Texas factory owner wants to develop a video surveillance system that can meet specific needs of the factory. NFRs to it will be:

  • Localization: USA, language — American English
  • Scalability: 1 factory, 10 security officers, up to 100 simultaneous cameras.

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. 

However, it’s a big game changer if we consider the potential of scaling from the very beginning, it saves a lot of money.

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.

Technical user stories also determine the browser and device support. You might’ve seen a note like “For the best experience, use the latest version of Chrome”? 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. 

Requirements for HOW the system should work

1. Effective performance

How to build it so that it works well? What does “well” even mean?

Example: Let’s take the same video surveillance system. If we want it to work well, then the video quality should be high (say, Full HD). But at the same time, we want to optimize server costs 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. 

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

2. Security

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 IBM data breach report.

Examples of security requirements: 

  • The users of the platform should be over 18 y.o.
  • The payment processing gateway must be PCI DSS compliant.
  • 1-1 calls should be HIPPA compliant.
  • User profiles and data storage should be GDPR compliant.

3. Speed

Non-functional requirements also answer the “how fast” question, in case the speed is critical. 

Example: 

  • The results must load within 3 seconds.

4. Integrations

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

Examples:

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

And so on, so on, so on.

Let’s summarize

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:

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

Conclusion

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 MVP, it goes fil-rouge throughout the entire product life cycle.

Categories
Uncategorized

What Hosting Provider Suits You: AWS vs DigitalOcean vs Hetzner [2022]

CPS logos connected to a server icon with plain lines

Out of dozens cloud hosting providers in Fora Soft we usually consider and build our projects 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.

To know the cost of any of the servers listed for your project, use our Server cost calculator. It considers how many streamers and viewers you anticipate, and what quality your streaming service requires.

But first…

What is a cloud service and a cloud service provider (CSP)?

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. 

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. 

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.

AWS (Amazon Web Services)

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.

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. 

Why does AWS make a great solution

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. 

That results in a smaller chance of system crashing, better performance, and smoother user experience. 

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. 

Colorful icons in a cloud shape with AWS logo on top
AWS tools

But 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 how many users you expect in the first few months. 

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. 

DigitalOcean

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. 

Why does DigitalOcean make great solution

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. 

As for keeping it simple, DigitalOcean products have neat user-friendly interfaces with one-click deployments. 

DigitalOcean interface and functionality

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. 

But after all, the DigitalOcean server cost is almost 7 times less. 

Long story short, DigitalOcean is a great pick if it’s your first release or an MVP and you’re looking for a cheap yet reliable cloud.

Hetzner Cloud

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. 

Why does Hetzner Cloud make a great solution

Hetzner Cloud has all the essentials required to start an app, yet they keep prices low and affordable.  

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. 

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.

Another con is lack of agileness in choosing servers and tools, same as it is with Digital Ocean. 

Final thoughts

To sum it all up, here’re the essentials to consider when picking a CSP out of 3 listed:

  1. How many users do you expect to use your product at once?
  2. How fast do you plan to grow?
  3. Where are your users browsing from?

And now a quick summary on what each CSP:

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

DigitalOcean is a great pick for you if you’re looking for a low cost, yet reliable media server provider.

Hetzner Cloud will make it even cheaper, yet more suitable for Europe (but not limited by it). 

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.

To calculate your monthly server costs, use our Server cost calculator. And to know the overall price of a project, contact us at info@fora-soft.com or our Head of Sales Vadim on Skype: vadim_prushchik

Categories
Uncategorized

What Should Come After The 1st MVP Release For It to Be a Success?

A funny cat picture with the article alternative title

In Fora Soft, when we release a product for the first time, it’s already an MLP (Minimum lovable product). But usually the first milestone in product development is MVP (Minimum viable product) launch. However, it’s not a point to stop. But what to do next? What comes after the MVP release and how do you know the product is ready? The answers are in this article. 

Gather feedback from your users

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. 

Sign up for startup websites

Like these:

  1. Product Hunt 
  2. Indiehackers
  3. Betalist 

The scheme here is quite easy yet effective:

Your profit: 

  • feedback from real users = the “Do they need the product?” hypothesis testing 
  • badge on your website = trust level increase
Badge on a website

Test the platform on users

Determine your target audience 

TA is a group of people that are most likely interested in your product. They share some needs and wants or have similar ones. 

For instance, TA for an LMS-system is students and teachers that take and give lessons online. 

Test your product with focus groups

  1. 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.
  2. 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”.
  3. 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.
  4. 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?

Carry out a customer development interview

Customer development interview (Custdev) — a means to get data while in-depth interviewing TA. While carrying out a custdev you discover current top-of-mind needs, preferred means of communication and content types. You’ll need these for the promoting campaign later. 

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.

Custdev aims at discovering how and where your TA gets information and what particular points for ads placement will be the most effective. 

There’re some Rules:

  1. 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. 
  2. Make a questionnaire. With the same questions for each of the respondents to prove the hypothesis.
  3. 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. 
  4. Ask follow up questions.
  5. 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. 
  6. 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.

Questions you might want to ask

Process the feedback

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. 

How to process feedback correctly:

  1. Discuss the feedback with the team
  2. Brainstorm on possible solutions and improvements together
  3. Make up a to-do list for the next release. Use MoSCoW prioritization method (Must have, Should have, Could Have, Won’t have (this time)) to prioritize: 

1st Priority: 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. 

2nd Priority: features that are important for the current stage but aren’t that critical. A product Should have them in the next development sprint. 

3rd Priority: features that could make a product better if there was additional development budget. It’s what the product Could have at its best. 

4th Priority: features that will definitely not be in the product, at least for the next 2 timeboxes. It’s what it Won’t have. 

We recommend focusing on the 1st and 2nd priorities as they suggest most needed improvements for the current period of time. 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. 

Make changes to the product 

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

Onboarding

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.

Minor interface adjustments 

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. 

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. 

Referral system

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. 

Notifications

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. 

Custom email newsletters will work for web apps.

Text update applying Tone of Voice

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. 

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. 

Relevant ToV guarantees that users will perceive the information better, since they better understand how the product works. 

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. 

Promote the platform

Pick the promotion channels and plan the works

  1. Think of the concept
  • Pick the promotion channels 

Based on the custdev data make a list of the most potentially effective sites for placing advertising messages.
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.

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. 

  • Make your advertisement hypotheses (objectives) to test. Make them SMART 

For example, Facebook users will download the app 100 times within 2 weeks. 

  • Calculate the overall costs

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 (how many unique users will see the ad) and clicks you’ll get for your budget.

Agree on promotional posts with authors/admins personally. Consider the fees and taxes. 

2. 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.

If the campaign includes any social media marketing activity, make up a content-plan, a list of posts topics.

Launch a test campaign

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. 

Launch the campaign in the most effective channels

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. 

Final words

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 CommunityHill, Janson Media, and AppyBee cases.

Categories
Uncategorized

How to Test WebRTC Stream Quality? Use StreamTest Extension [Free]

StreamTest UI with the article title

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 — StreamTest

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. 

a stream page with a non WebRTC stream error
Non-WebRTC stream error

It’ll give you a live status on 7 essential parameters with an insight on the connection and stream behavior. 

Quick note for non-tech folks:

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. 

We are already working on making the plugin accessible for you, so you could test your live streams easily, guys. So follow us on LinkedIn to stay turned. 

TestStream report UI
Video conference live status

Frame rate 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.

Video and Audio delay. 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.

Packet loss. 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%. 

Resolution. The higher the better. It mostly depends on the participant’s camera and the device you’re using to chat. 

Freezes and stalls. 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 && dt > 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. 

Bitrate. This indicator is responsible for how smooth the picture is, the higher the indicator the smoother the picture.

Video and Audio codec — for a developer to know how the data is compressed.

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

Table withe report metrics coloring
StreamTest live status colors meaning

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. 

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. 

To test live streams, download this WebRTC tester for your Chrome from the official store here. For free. 

Categories
Uncategorized

How to Implement Delayed Messages with RabbitMQ? Code Examples

Graphic article cover with colorful command windows

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.

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).

But with both these solutions there’s a scaling problem:

  • There’re several servers so it might be unclear on which one to run the task
  • The selected server might crash
  • The node might get deleted for freed up resources

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:

  1. Create 2 exchangers: regular and delayed one
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: {},
});

2. In each of the exchangers create queues with the same binding type but different names.

For HELLO_EXCHANGE:

queues: { 
        WORLD: {
            name: 'hello.world', // subscribe to this queue
            binding: 'hello.world',
            options: {
                durable: true,
            },
        },
    },

For HELLO_DELAYED_EXCHANGE:

  queues: {
        WORLD: {
            name: 'helloDelayed.world',
            binding: 'hello.world',
            options: {
                durable: true,
                queueMode: 'lazy', // set the message to remain in the hard memory
            },
        }

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.

  arguments: {
                    'x-dead-letter-exchange': HELLO_EXCHANGE.name, // set the queue to transfer the message to once it’s dead
                }

3. Publish the message to the delayed-exchanger’s queue with the expiration period

// 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) 
});

Once the delayed message expires, it will go to the regular exchanger’s queue.

Now you only have to set a consumer for the regular exchanger’s queue:

// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () => 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 }) => {
    const result = await world({ name: payload.name });
    logger.info(result.message);
    // await publishHelloDelayedWorld({ name: payload.name }); // if you need to process the message again
};

Profit!

If you need to run the action periodically, publish the message to the delayed exchanger again at the end of the consumer section. 

    // await publishHelloDelayedWorld({ name: payload.name });

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.

Eventually, this is what you get:

  1. Create the exchangers and queues
// 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
                },
            },
        },
    },
});

2. Add the publisher that will send the message to the delayed queue


// 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)
});

3. Add the consumer for the regular exchanger’s queue


// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () => 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 }) => {
    const result = await world({ name: payload.name });
    logger.info(result.message);
    // await publishHelloDelayedWorld({ name: payload.name }); // if you need to process the message again
};

4. Profit!

There’s also a plugin that does this work for you and makes the implementation easier. You only create one exchanger, one queue, one publisher, and one consumer.

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. 

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.

// 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,
            },
        },
    },
});

Add publisher that sends the messages to the delayed queue: 

export const publishHelloPluginDelayedWorld = createPublisher({
    exchangeName: exchangeNamePluginDelayed,
    queue: WORLD_PLUGIN_DELAYED,
    delayInMs: 60000,  // specify when the message should die (60s)
});

Add consumer to the queue:

// services/base-service/src/broker/hello/consumer.ts
export const initHelloExchange = () => 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 }) => {
    const result = await world({ name: payload.name });
    logger.info(result.message);
};

Aaand — you’re done!

We regularly use RabbitMQ in our projects. For instance, check out its use case in Janson Media internet TV portfolio. It’s a movie renting service, but make it digital. 

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. 

Hopefully, implementing delayed messages won’t be like falling down the rabbit hole for you anymore (if it ever was) 🙂

Categories
Uncategorized

Richard from Community Hill, ‘I’m glad that Fora Soft has designers, analytics, testers.’

Here’s an interview with Richard, the owner of Community Hill. Richard’s entrepreneurship has been going on for 10 years – since the times Amazon was selling books. Now he’s working with Fora Soft, which is his last hope.

What do you have to expect going into work with Fora Soft? What can we teach an experienced entrepreneur who had worked with many developers before coming to Fora Soft? The answers are in the interview.

I also tried my best to find out the problems Richard might’ve had with Fora Soft, so that the feedback is truly genuine. It turned out to be a difficult task, as everything has been spot on. Enjoy!


Nikita: What is Community Hill and who is it for? 

Richard: Thank you for this opportunity. Community Hill is an online platform with people of various communities, mainly the towns and the villages where people live. People sell various items, usually household items, including furniture, vehicles and others. Service providers post their services. For instance, electricians. So on that platform, people post everything, and if anyone is interested, contact them. They plan a time and location to meet and then they do the transaction. That’s what Community Hill is about. We’re building the community together, you know? 

Nikita: Cool. So you’ve come to Fora Soft. When did this happen? 

Richard: That was last year. Probably August or September? I went to an online auction platform first. I was looking for a team that could really make a good product. And then one of the team members of Fora Soft contacted me. He told me that we’d get in touch. I’m glad that we got it started. So I’ve been with you for 9-10 months. And I’m still with you because we have to do the 2nd phase. 

Nikita: That’s very good to hear. But before Fora Soft, was there any company that you were going to work with? Perhaps, Fora Soft wasn’t your first choice? 

Richard: Yes. At first I contacted one of the programmers. That platform where I went has so many programmers. You can never know whether someone really knows what he’s doing or whether he’s also outsourcing somewhere else. So the first person didn’t really do a good job at all. So I kind of lost hope in these individual freelancers. I decided that I needed a team of people that can really do something. And when I checked on that, all of a sudden Fora Soft showed up. Nothing else showed up, actually. I read the reviews on Fora Soft and it started from there. I didn’t look for anything else. So, that’s how we met.

Nikita:  You mentioned having the team in Fora Soft, a project team consists of developers, project managers, designers, QA… We’ve got marketing, promotion and so on and so forth. During the production of your app, did you ever feel that you really need all those people? Or was it like, “I don’t really understand why I need so many people, and I’m good with like 2 or 3 of them, not the whole team?” 

Richard: I needed all of them. Let me give you an example. For instance, designing a logo. I’m not an artist. I don’t even have the knowledge of how a good logo should look. So I just needed everyone to come on board because I didn’t know much about these things. I didn’t know how the best user stories should be. So I just needed a team of everyone to be on board.

And then when I was told that we even have testers, I was so glad that they had that team.

Nikita: Over the time of us working together, was there anything that you wish that Fora Soft would improve, maybe some downsides of working with us? 

Richard: I haven’t come across anything because Fora Soft is good at communicating. You keep in touch. I always communicate with the programmer, the project manager, the designer. Because of that constant communication, there hasn’t been a gap for doubt. Like every time I have an issue or an idea, I usually ask them and then we find a solution right away. We could also find a date to have a meeting and talk about it.

Nikita: Good to hear. Let’s talk a little bit about your app. So it’s an iOS app. Are you planning on going to Android or Web or something else? 

Richard: Oh, yeah, definitely. If we get more funding, I want us to finish this 2nd phase of iOS and then I also want us to do the Android version or the web version as well. 

Nikita: Okay. And Community Hill is currently an MVP, right? 

Richard: Correct. 

Nikita: During this MVP, did you have any people to test the app? Maybe yourself, your family, or friends. 

Richard: Yeah, sure. It’s been myself at the moment. I haven’t been able to ask any family members to test, so it’s just me and the programmer for now.

Nikita: I guess you did come across some bugs because, unfortunately, they’re imminent. Do you feel that there were lots of bugs or were they kept to a minimum? 

Richard: Well, at some point, as I was testing the app – the MVP –  it crashed. And then I mentioned it to the programmer, and he said that he was going to check it out to find a solution for it. Other than that, I didn’t see any other bugs on my side. Maybe on their side, they might have seen some because so many people were testing, so they could identify more issues. But on my side, I didn’t see anything else. 

Nikita: Right. And after the developer said that he was going to look into the problem, did he keep his promise? 

Richard: Yes, he told me that they have also identified other issues and they are going to work on them. And we are yet to have the meeting this week (the meeting went peachy, Fora Soft resolved everything). We’re gonna discuss the issues that they found. So I would say he kept his promise. 

Nikita: Is there something you want to add or say about Fora Soft that relate to our other clients?

Richard:

I would say that any anyone who comes Fora Soft should be really available for constant communication.

That’s what really helps to keep the project going. If one is really busy and not able to keep in touch, I think it will be so hard to keep the project moving. It’s all about communication. You’re on the same page with the programmers. Your expectations and their expectations are on the same level. I think that’s the most important thing – be ready to keep in touch with all the team members. Starting with that, with the analytic, then programmers, and all those people, it’s about communication. 

Nikita: Right. And actually, I have one more question that I kind of forgot to ask in the beginning. Richard, do you yourself have some kind of technical background? 

Richard: A little bit. I’ve always had the passion of online businesses. I started out venturing into online businesses like 10 years ago, those years when Amazon was just getting started, when they were just selling books. I had this idea of the market place, but I didn’t have the money. So I reached out to the local programmers and they really did do a good job. They didn’t do what I really wanted. So I’ve been trying out this field of online businesses for a long time. During that time, of course, I’ve come to learn a little bit of what programing is all about, what a programmer is and all that kind of stuff. I’ve developed a little bit of technical knowledge in that field. But I don’t really have that much technical background, just a little bit, only because I’ve been trying out this field for a very long time. I must say that Fora Soft is my last try. If it fails, I’m out of it because it’s been like 10 years. I’m trying this out since the time Amazon was selling books. I was building ideas on how to make a good marketplace. It’s been a long time. So I would say Fora Soft is my last try. If it fails, I let it go. 

Nikita: Well, I guess I can speak on behalf of Fora Soft, that we’ll do our best to satisfy your needs. And actually what I wanted to ask is that you barely have some technical background. You are not a developer by any means, as far as I understand. Did you ever feel that you are lacking the skills to produce Community Hill with Fora Soft? Or did it feel like you don’t actually need to understand the codes or anything like that? You can just give Fora Soft an assignment and expect a result, and you can give this assignment using some human language, not developer language. 

Richard: Yeah, I knew that I didn’t really need to be a developer, but I knew what final product should look like. Because, like I said, I’ve been trying out these things. I’ve seen how Amazon has been changing the way you interact with the app, the website, all those things that they do on their marketplaces. So I’ve kind of got the knowledge on how the best product should look like. So I said, I don’t really have to be a developer, but I know how a final product should look like. 

Nikita: Can you please rate Fora Soft on a scale of ten in terms of communication, professionalism, and determination in the project’s involvement, perhaps. 

Richard: Oh, it’s ten out of ten. The local developers and freelancers I interacted with before I came to Fora Soft, they didn’t even tell me about user stories.

I first heard about user stories from Fora Soft.

I’d never heard that word. The freelancers I reached out to before, they didn’t even know these things. Like they didn’t have the professional knowledge of how a project should run. They didn’t even give me a development plan. I first saw a development plan from Fora Soft. These freelancers didn’t have those things. They didn’t have that kind of communication. So I’m glad that I chose Fora Soft. The rating is 10 out of 10. 


So, that’s it! Wanna, just like Richard, enjoy all the best that Fora Soft has to offer? Make sure to contact us using the contact form!

Not convinced yet? Read more customer interviews:

Jesse, Vodeo – a movie renting platform
Anthony, Speakk – a mobile messenger that doesn’t consume traffic
Jan, AppyBee – a booking platform
Naseem, Mobytap – a business video review platform
Ali, TapeReal – a video social network

Categories
Uncategorized

How To Implement Screen Sharing in iOS App using ReplayKit and App Extension

Intro

Screen sharing – capturing user’s display and demonstrating it to peers during a video call. 

There’re 2 ways how you can implement screen sharing into your iOS app:

  1. Screen sharing in app. It suggests that a user can only share their screen from one particular app. If they minimize the app window, broadcasting will stop. It’s quite easy to implement.
  2. Screen sharing with extensions. This approach enables screen sharing from almost any point of the OS: e.g. Homescreen, external apps, system settings. But the implementation might be quite time-consuming.

In this article, we’ll share guides on both.

Screen sharing in app

Starting off easy – how to screen share within an app. We’ll use an Apple Framework, ReplayKit.

import ReplayKit

class ScreenShareViewController: UIViewController {

		lazy var startScreenShareButton: UIButton = {
        let button = UIButton()
        button.setTitle("Start screen share", for: .normal)
        button.setTitleColor(.systemGreen, for: .normal)
        return button
    }()
    
    lazy var stopScreenShareButton: UIButton = {
        let button = UIButton()
        button.setTitle("Stop screen share", for: .normal)
        button.setTitleColor(.systemRed, for: .normal)
        return button
    }()

		lazy var changeBgColorButton: UIButton = {
        let button = UIButton()
        button.setTitle("Change background color", for: .normal)
        button.setTitleColor(.gray, for: .normal)
        return button
    }()
    
    lazy var videoImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.image = UIImage(systemName: "rectangle.slash")
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()
}

Here we added it to the ViewController where recording, background color change buttons and imageView are – this is where the captured video will appear later.

the ViewController

To capture the screen, we address the RPScreenRecorder.shared() class and then call startCapture(handler: completionHandler:).

@objc func startScreenShareButtonTapped() {
		RPScreenRecorder.shared().startCapture { sampleBuffer, sampleBufferType, error in
				self.handleSampleBuffer(sampleBuffer, sampleType: sampleBufferType)
            if let error = error {
                print(error.localizedDescription)
            }
        } completionHandler: { error in
            print(error?.localizedDescription)
        }
}

Then the app asks for a permission to capture the screen: 

the permission pop-up

ReplayKit starts generating a CMSampleBuffer stream for each media type – audio or video. The stream contains the media fragment itself – the captured video – and all necessary information. 

func handleSampleBuffer(_ sampleBuffer: CMSampleBuffer, sampleType: RPSampleBufferType ) {
        switch sampleType {
        case .video:
            handleVideoFrame(sampleBuffer: sampleBuffer)
        case .audioApp:
//             handle audio app
            break
        case .audioMic:
//             handle audio mic
            break
        }
    }

The function converted into the UIImage type will then process each generated videoshot and display it on the screen.

func handleVideoFrame(sampleBuffer: CMSampleBuffer) {
        let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
        let ciimage = CIImage(cvPixelBuffer: imageBuffer)
        
        let context = CIContext(options: nil)
        var cgImage = context.createCGImage(ciimage, from: ciimage.extent)!
        let image = UIImage(cgImage: cgImage)
        render(image: image)
}

Here’s what it looks like:

generated frames

Captured screen broadcasting in WebRTC 

Usual setting: during a video call one peer wants to demonstrate the other what’s up on their screen. WebRTC is a great pick for it.

WebRTC connects 2 clients to deliver video data without any additional servers – it’s peer-to-peer connection (p2p). Check out this article to learn about it in detail. 

Data streams that clients exchange are media streams that contain audio and video streams. A video stream might be a camera image or a screen image.

To establish p2p connection successfully, configure a local mediastream that will further be delivered to the session descriptor. To do that, get an object of the RTCPeerConnectionFactory class and add the media stream packed with audio and video tracks to it.

func start(peerConnectionFactory: RTCPeerConnectionFactory) {

        self.peerConnectionFactory = peerConnectionFactory
        if self.localMediaStream != nil {
            self.startBroadcast()
        } else {
            let streamLabel = UUID().uuidString.replacingOccurrences(of: "-", with: "")
            self.localMediaStream = peerConnectionFactory.mediaStream(withStreamId: "\\(streamLabel)")
            
            let audioTrack = peerConnectionFactory.audioTrack(withTrackId: "\\(streamLabel)a0")
            self.localMediaStream?.addAudioTrack(audioTrack)

            self.videoSource = peerConnectionFactory.videoSource()
            self.screenVideoCapturer = RTCVideoCapturer(delegate: videoSource!)
            self.startBroadcast()
            
            self.localVideoTrack = peerConnectionFactory.videoTrack(with: videoSource!, trackId: "\\(streamLabel)v0")
            if let videoTrack = self.localVideoTrack  {
                self.localMediaStream?.addVideoTrack(videoTrack)
            }
            self.configureScreenCapturerPreview()
        }
    }

Pay attention to the video track configuration:

func handleSampleBuffer(sampleBuffer: CMSampleBuffer, type: RPSampleBufferType) {
        if type == .video {
            guard let videoSource = videoSource,
                  let screenVideoCapturer = screenVideoCapturer,
                  let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
            
            let width = CVPixelBufferGetWidth(pixelBuffer)
            let height = CVPixelBufferGetHeight(pixelBuffer)
            videoSource.adaptOutputFormat(toWidth: Int32(width), height: Int32(height), fps: 24)
            
            let rtcpixelBuffer = RTCCVPixelBuffer(pixelBuffer: pixelBuffer)
            let timestamp = NSDate().timeIntervalSince1970 * 1000 * 1000
            
            let videoFrame = RTCVideoFrame(buffer: rtcpixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: Int64(timestamp))
            videoSource.capturer(screenVideoCapturer, didCapture: videoFrame)
        }
}

Screen sharing with App Extension

Since iOS is a quite closed and highly protected OS, it’s not that easy to address storage space outside an app. To let developers access certain features outside an app, Apple created App Extensions – external apps with access to certain relationships in iOS. They operate according to their types. App Extensions and the main app (let’s call it Containing app) don’t interact with each other directly but can share a data storing container. To ensure that, create an AppGroup on the Apple Developer website, then link the group with the Containing App and App Extension. 

containing app and extension relation
Scheme of data exchange between entities

Now to devising the App Extension. Create a new Target and select Broadcast Upload Extension. It has access to the recording stream and its further processing. Create and set up the App Group between targets. Now you can see the created folder with App Extension. There’re Info.plist, the extension file, and the swift SampleHandler file. There’s also a class with the same name written in SampleHandler that the recorded stream will process. 

The methods we can operate with are already written in this class as well: 

override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?)
override func broadcastPaused() 
override func broadcastResumed() 
override func broadcastFinished()
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType)

We know what they’re responsible for by their names. All of them, but the last one. It’s where the last CMSampleBuffer and its type arrives. In case the buffer type is .video, this is where the last shot will be.

Now let’s get to implementing screen sharing with launching iOS Broadcast. To start off, we demonstrate the RPSystemBroadcastPickerView itself and set the extension to call.

let frame = CGRect(x: 0, y: 0, width: 60, height: 60)
let systemBroadcastPicker = RPSystemBroadcastPickerView(frame: frame)
systemBroadcastPicker.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin]
if let url = Bundle.main.url(forResource: "<OurName>BroadcastExtension", withExtension: "appex", subdirectory: "PlugIns") {
    if let bundle = Bundle(url: url) {
           systemBroadcastPicker.preferredExtension = bundle.bundleIdentifier
     }
}
view.addSubview(systemBroadcastPicker)

Once a user taps “Start broadcast” the broadcast will start and the selected extension will process the state and the stream itself. But how will the Containing App know this? Since the storage container is shared, we can exchange data via the file system – e.g. UserDefaults(suiteName) and FileManager. With it we can set up a timer, check up the states within certain periods of time, record and read data along a certain track. An alternative to that is to launch a local web-socket server and address it. But in this article we’ll only cover exchanging via files.

Write the BroadcastStatusManagerImpl class that will record current broadcast status as well as communicate to the delegate on status alterations. We’ll check on the updated info using a timer with 0.5 sec frequency. 

protocol BroadcastStatusSubscriber: AnyObject {
    func onChange(status: Bool)
}

protocol BroadcastStatusManager: AnyObject {
    func start()
    func stop()
    func subscribe(_ subscriber: BroadcastStatusSubscriber)
}

final class BroadcastStatusManagerImpl: BroadcastStatusManager {

    // MARK: Private properties

    private let suiteName = "group.com.<YourOrganizationName>.<>"
    private let forKey = "broadcastIsActive"

    private weak var subscriber: BroadcastStatusSubscriber?
    private var isActiveTimer: DispatchTimer?
    private var isActive = false

    deinit {
        isActiveTimer = nil
    }

    // MARK: Public methods

    func start() {
        setStatus(true)
    }

    func stop() {
        setStatus(false)
    }

    func subscribe(_ subscriber: BroadcastStatusSubscriber) {
        self.subscriber = subscriber
        isActive = getStatus()

        isActiveTimer = DispatchTimer(timeout: 0.5, repeat: true, completion: { [weak self] in
            guard let self = self else { return }

            let newStatus = self.getStatus()

            guard self.isActive != newStatus else { return }

            self.isActive = newStatus
            self.subscriber?.onChange(status: newStatus)
        }, queue: DispatchQueue.main)

        isActiveTimer?.start()
    }

    // MARK: Private methods

    private func setStatus(_ status: Bool) {
        UserDefaults(suiteName: suiteName)?.set(status, forKey: forKey)
    }

    private func getStatus() -> Bool {
        UserDefaults(suiteName: suiteName)?.bool(forKey: forKey) ?? false
    }
}

Now we create samples of BroadcastStatusManagerImpl to the App Extension and the Containing App, so that they know the broadcast state and record it. The Containing App can’t stop the broadcast directly. This is why we subscribe to the state – this way, when it reports false, App Extension will terminate broadcasting, using the finishBroadcastWithError method. Even though, in fact, we end it with no error, this is the only method that Apple SDK provides for program broadcast termination. 

extension SampleHandler: BroadcastStatusSubscriber {
    func onChange(status: Bool) {
        if status == false {
            finishBroadcastWithError(NSError(domain: "<YourName>BroadcastExtension", code: 1, userInfo: [
                NSLocalizedDescriptionKey: "Broadcast completed"
            ]))
        }
    }
}

Now both apps know when the broadcast started and ended. Then, we need to deliver data from the last shot. To do that, we create the PixelBufferSerializer class where we declare the serializing and deserializing methods. In the SampleHandler’s processSampleBuffer method we convert CMSampleBuffer to CVPixelBuffer and then serialize it to Data. When serializing to Data it’s important to record the format type, height, width and processing increment for each surface in it. In this particular case we have two of them: luminance and chrominance, and their data. To get the buffer data, use CVPixelBuffer-kind functions.

While testing from iOS to Android we’ve faced this problem: the device just wouldn’t display the screen shared. It’s that Android OS doesn’t support the irregular resolution the video had. We’ve solved it by just turning it into 1080×720. 

Once having serialized into Data, record the link to the bytes gained into the file.

memcpy(mappedFile.memory, baseAddress, data.count)

Then create the BroadcastBufferContext class in the Containing App. Its operation logic is alike BroadcastStatusManagerImpl: the file discerns each timer iteration and reports on the data for further processing. The stream itself comes in 60 FPS, but it’s better to read it with 30 FPS, since the system doesn’t perform well when processing in 60 FPS due to lack of the resource. 

func subscribe(_ subscriber: BroadcastBufferContextSubscriber) {
        self.subscriber = subscriber

        framePollTimer = DispatchTimer(timeout: 1.0 / 30.0, repeat: true, completion: { [weak self] in
            guard let mappedFile = self?.mappedFile else {
                return
            }

            var orientationValue: Int32 = 0
            mappedFile.read(at: 0 ..< 4, to: &orientationValue)
            self?.subscriber?.newFrame(Data(
                bytesNoCopy: mappedFile.memory.advanced(by: 4),
                count: mappedFile.size - 4,
                deallocator: .none
            ))
        }, queue: DispatchQueue.main)
        framePollTimer?.start()
    }

Deserialize it all back to CVPixelBuffer, likewise we serialized it but in reverse. Then we configure the video track by setting up the extension and FPS.

videoSource.adaptOutputFormat(toWidth: Int32(width), height: Int32(height), fps: 60)

Now add the frame RTCVideoFrame(buffer: rtcpixelBuffer, rotation: RTCVideoRotation._0, timeStampNs: Int64(timestamp)). This track goes to the local stream.

localMediaStream.addVideoTrack(videoTrack)

Conclusion 

Implementing screen sharing in iOS is not that easy as it may seem. Reservedness and security of the OS force developers into looking for workarounds to deal with such tasks. We’ve found some – check out the result in our Fora Soft Video Calls app. Download on AppStore.

Categories
Uncategorized

How to Save Time & Money By Sharing Your Source Code With Devs

When you approach us with not just a project idea, but an existing code, we’ll ask you to share it with us. Don’t worry, it will help you save lots of time and maybe improve a product. Read to find out how!

Many customers come to us with a project already at some stage of readiness. It may be a draft version, which needs the hands of professionals before the official release; or the already established product, which we’re glad to improve.

Anyway, we ask clients to share the source code of an existing project. As a rule of thumb, this doesn’t cause any difficulties. The opposite happens as well: our customers wonder why we need existing code as we will create our own, and what are the risks? Should you share your source code with a new developer / between development teams or not?

Let us explain it all to you.

How can we improve the application using your code?

  • Test the whole platform, not just our part 

Even if the task is a standalone module that adds new features to an existing project, there’s only 1 criterion for readiness: a well-functioning system.

To confirm that the new module is well integrated into the existing system, we need to accurately recreate the real environment (a test environment) and test it comprehensively. What if a new feature – such as the ability to translate speech on the fly – interferes with existing functionality? 

  • By ensuring full compatibility

It happens that the existing code was written quite a long time ago and uses previous versions of various tools. In this case, the only way to be sure that the new module will work well in a live infrastructure is to test them together and resolve possible contradictions.

  • By ensuring quick support for the new functionality

Integration of several systems (e.g. an existing project and a new module) always requires coordinated efforts of the teams: the one which supports the live product and the one which created the new functionality. In order for the integration to go quickly and for the teams to interact effectively, it is necessary for both parties to navigate both parts of the project. Then your team can clarify requirements at any time, and our team can implement them.

  • (Maybe) we’ll improve what’s already working

We have 17 years of experience in developing online multimedia platforms for various purposes. It often happens that we have effective ways to solve important problems – from scaling to saving traffic – that will make the already implemented functionality more reliable and less demanding.

In other words, being able to open the existing source code is the main guarantee that developing add-ons to the live platform will go as fast as possible and save you money and time before release.

Why you don’t have to worry about your code

You don’t send your child to an unknown kindergarten without being sure that nothing bad will happen to him. Your code is your baby, and we guarantee that, should you share the code with us, we won’t do things such as:

  • We won’t re-use it

Our clients’ intellectual property is protected by both the law and our reputation.

The contract we conclude with our clients includes a clause about non-disclosure of the data constituting the intellectual property (NDA). This means that all the code that we receive from a client is used to perform his and only his tasks.

  • We won’t edit it without the client’s knowledge

In all projects, we adhere to strict rules for updating code in the client repository. Any new code is uploaded to a separate branch, and it is up to the customer to decide whether or not to make these changes to the main branches of the project. This means one thing: whether it’s just our team working on the platform, or several independent teams of specialists, the client always has the final say.

But I really can’t share the source code! What to do then?

Of course, there are situations where access to the source code is really impossible. Or it simply doesn’t exist, because we are talking about a hardware platform that requires software.

If access to the source code is impossible because it belongs to a third party. 

For example, you are developing a system for a large corporate contractor, and you’ve decided to turn to a video communications specialist.

Our analysts and developers will help you formulate a detailed requirements specification: how, where, in what format and what data should the component created by us transmit? Together we will draw up documentation on which we can work.

If your project uses proprietary solutions, as a rule, they are documented in detail. In this case, access to documentation is an important factor for fast development and easy integration.

If there is no access to the sources, because the previous developers have handed over the finished product, and it is impossible to contact them

Development team rushes to the rescue! We will try to extract as much data as possible from the finished system and restore the source code. The features of JavaScript, our main development language, and our experience make it possible.

If you have hardware, but no software for it yet.

The main thing we need is a sample and as detailed specifications as possible: how do your devices work, what OS do they use, what is their processing power? This data will help us to create software to perform the required tasks on the existing devices.

We hope our explanation was convincing enough for you not to hesitate to share the code.  If you have any questions left, please don’t hesitate to drop us a message via the contact form, and we’ll get back to you ASAP.