Dive into the latest industry wisdom from
our experts.
Avoid Common Traps in Product Discovery
Success requires a well-crafted plan. And to develop such a plan, companies rely on the invaluable insights and data gathered through the implementation of a product discovery process. This process entails comprehending customer needs, market trends, and technological advancements, resulting in products that genuinely resonate with users. However, even experienced product teams can unwittingly encounter common traps that hinder the effectiveness of the discovery process. In this article, we aim to shed light on these prevalent mistakes and offer practical insights on how to avoid them.
Focusing solely on the product & ignoring customer needs
The most common mistake during product discovery is placing excessive emphasis on the product itself and losing sight of the bigger picture. Instead of fixating on the intricacies and desired product functionalities, it's crucial to prioritize understanding your target audience and their specific needs and pain points. Neglecting your users can be a detrimental mistake that sets you up for failure. A product cannot thrive in a competitive market without a user-centric approach.
Effective customer research encompasses a range of methods, including in-depth interviews, surveys, market analysis, and user testing. By actively engaging customers in the discovery process, you can convey an in-depth understanding of their problems, desired outcomes, and expectations for a solution. This valuable insight acts as a guiding compass for product development, informing decisions regarding features, functionalities, and overall product strategy.
Not understanding what the real problem is
Without a clear understanding of the real problem, you risk investing time and resources in building solutions that miss the mark and fail to provide the desired value to customers. This misstep can lead to a disconnect between the product and the target market's needs, resulting in low adoption rates and limited success. Furthermore, it creates an opportunity for competitors to seize the moment and offer the right solution at the right time.
Avoiding this mistake is easily achievable through detailed research and customer interviews. Neglecting market research can cause potential opportunities to be overlooked and increase the likelihood of failure. Without proper investigation, you are left operating on assumptions and guesswork.
Not involving technical team
Let's be realistic. While imagination is essential, it's highly important to find someone who can assess if your plans are grounded in reality. This is where the technical team and experts play a vital role, offering valuable insights into user behavior, how customers interact with your products, and which features they would like to see further developed. The technical team includes engineers, coders, designers, and other experts who possess in-depth knowledge of the system you aim to produce. Their understanding ensures a comprehensive grasp of the inner workings and intricacies of the product.
Your technical team is not the only group of experts you require. Underestimating the need for experts in the product discovery process can be a critical oversight. At Cleevio, we recognize that generating an innovative product goes beyond having a good idea. It demands a process of dedicated focus, efficient learning, and continuous validation to guarantee the delivery of exceptional value to our clients. We crafted our approach to pinpoint the highest value we can offer to customers facing specific and significant challenges. Simultaneously, we aim to minimize risks, accelerate time-to-market, and maximize your financial investment.
Product Discovery Fundamentals You Should Know
What sets apart a successful product from one that fails in the market? It’s the underestimated significance of preparation and, most importantly, the discovery phase. Unfortunately, many companies fail to prioritize the crucial task of discovering their users’ needs. Consequently, they often end up developing products with mere „nice to have“ features rather than delivering something essential to their customers. It comes as no surprise that a staggering 63% of all new tech businesses in the US experience failure within the first 5 years.
Meeting Customers' Needs for Competitive Success
That may be unfortunate for them, but it presents a fantastic opportunity for you. Gain a competitive advantage by incorporating in-depth research and implementing product discovery into your decision-making process.
During the discovery phase, we identify the best value we can offer to your customers facing specific and significant challenges. This approach aims to minimize risks, accelerate time-to-market, and maximize your financial investment. How do we achieve this? By dedicating time to comprehending the market, trends, and most importantly, customer needs. We then pinpoint the major pain points and define an optimal solution that aligns with clients' expectations and budget.
Best Time for Product Discovery
The right time to consider the discovery phase is when your products and services no longer align with the company's mission or underperform. It's time to initiate a change by analyzing customer usage data, staying abreast of industry trends, and mastering the craft of delivering products on time and within budget.
Strategic companies proactively avoid pitfalls by prioritizing the implementation of the discovery phase before product development. By doing so, businesses can achieve significant cost reductions of 30-40% in development and operations. Gain valuable insights into industry best practices through our ebook, "The Digital Entrepreneur’s Holy Grail: Essential Topics for Startup Victory."
Key Learnings For You
By implementing the right discovery strategy, you can mitigate numerous risks through a well-executed discovery phase, such as avoiding misalignment with customer needs, streamlining user experience by eliminating excessive features and ensuring sustainable product growth.
To achieve this, prioritize understanding customer needs, staying informed about industry trends, engaging in meaningful discussions with your tech team, testing user prototypes, and establishing a realistic business model. And remember, you don’t have to face it alone. By choosing the right partner, you can simplify the entire process and pave the way for smoother execution.
What is next? Read our ebook, "The Digital Entrepreneur’s Holy Grail: Essential Topics for Startup Victory" or reach out to our team for more information.
Innovating for Change: Prague AI Hackathon Recap
As a company committed to innovation and creativity, we were thrilled to co-host our first-ever hackathon last weekend. Over the course of the event, we witnessed incredible teamwork, problem-solving, and out-of-the-box thinking, as participants worked tirelessly to bring their ideas to life. We were blown away by the talent and passion of all those involved and are excited to share some of the highlights from this unforgettable weekend.
The Ultimate Goal
At the Prague AI Hackathon, we focused on creating a collaborative and engaging environment by prioritizing social impact, participants' education, and networking. We aimed to explore the potential of AI models and how to apply them to real-world problems.
Through teamwork and innovation, participants pushed beyond their limits and developed creative solutions to the challenges presented.
We sought to not only push the limits of AI models but also to create an impact on society. The participants' innovative solutions had the potential to make a real difference in people's lives.
See for yourself!
Presenting the Winners: Worwio
The winning solution at the Prague AI Hackathon was a tool that utilized deep learning models to create an audio track for a video in the selected tool. By employing advanced signal processing techniques and leveraging the power of AI, the tool automatically generates high-quality audio in a chosen language that is perfectly synchronized with the original video.
The tool's intelligent algorithms were able to analyze the video's content and generate a suitable translated audio track based on the context, resulting in a seamless and immersive viewing experience for the end users.
Conclusion
We believe the Prague AI Hackathon was a successful event that focused on creating an environment of innovation and creativity by prioritizing social impact, education, and networking. The participants worked tirelessly to develop creative solutions to real-world problems using AI models and showcased the potential of AI models and how to use them to create a positive impact on society.
Leveraging LLMs in the Corporate Sphere
The corporate landscape is experiencing a transformative shift with the integration of Large Language Models (LLMs) such as OpenAI's GPT-4. These AI-driven tools offer specific, tangible benefits in cost reduction, employee onboarding, and enhancing workplace experiences. In this article, we delve into real-world examples that demonstrate how LLMs are transforming the corporate environment.
Cost Reduction Through LLMs
Automating Customer Service
LLMs are being employed to handle customer inquiries more efficiently. For instance, the use of chatbots powered by GPT-4 can provide quick, accurate responses to customers' questions, resulting in decreased waiting times and a reduced need for human customer service agents.
Enhancing Content Creation
LLMs can generate high-quality content at a fraction of the cost of traditional copywriting services. Businesses can utilize AI-generated content for marketing campaigns, social media updates, and website copy, significantly reducing content creation costs.
Supply Chain Optimization
LLMs can analyze vast amounts of data to identify patterns, trends, and anomalies, enabling companies to optimize their supply chains. Early adopters who have successfully implemented AI-enabled supply-chain management have experienced improvements in logistics costs by 15 percent, inventory levels by 35 percent, and service levels by 65 percent compared with slower-moving competitors.1 For example, Walmart uses AI to manage its vast inventory, resulting in reduced waste, lower storage costs, and improved customer satisfaction.2
Route Optimization for Transportation
Companies like UPS are leveraging AI to reduce costs by planning the most efficient routes for their fleets. UPS uses its proprietary AI-driven system, ORION (On-Road Integrated Optimization and Navigation), to analyze numerous data points and determine the optimal route for drivers. This has resulted in significant reductions in fuel consumption, vehicle maintenance expenses, and overall delivery times.3
Since ORION’s initial deployment, it has saved UPS about 100 million miles and 10 million gallons of fuel per year.4
Revolutionizing Employee Onboarding
Customized Training Solutions
LLMs can help create personalized onboarding experiences that cater to each employee's unique needs. For instance, Amazon uses AI to tailor individual training programs for warehouse employees, ensuring they are equipped with the skills and knowledge required for their specific role and continuously tracking how each employee performs. 5
Intelligent Assistance
New employees can benefit from AI-driven virtual assistants that offer support and guidance throughout the onboarding process. IBM's Watson Assistant, for example, provides personalized answers to employees' questions and helps them navigate company systems and procedures.6
Elevating the Employee Experience
Collaborative Tools
LLMs can help improve cross-team collaboration by breaking down language barriers and summarizing complex information. For example, tools like Google Translate & DeepL use AI to provide real-time language translation, enabling teams from diverse backgrounds to communicate and collaborate seamlessly.
Workflow Optimization
LLMs can analyze employees' daily tasks to identify bottlenecks and inefficiencies. This data-driven approach allows for better allocation of resources and more streamlined workflows. For example, JPMorgan Chase & Co. implemented its AI system, COIN, to analyze and extract relevant data from legal documents, saving countless hours of manual work.7
Mental Health and Well-being Support
LLMs can be used to create AI-driven well-being solutions, such as mood trackers and stress management tools. For example, Headspace, a popular meditation app, employs AI to provide personalized recommendations and content, fostering better mental health and work-life balance.8
Conclusion
LLMs are more than just a technological advancement; they represent a paradigm shift in the way businesses operate. By providing specific, real-world applications, LLMs can effectively reduce costs, streamline employee onboarding, and elevate the workplace experience. As AI technology continues to evolve, businesses that leverage the full potential of LLMs will stay ahead of the curve, maximizing efficiency, productivity, and employee satisfaction.
- https://www.mckinsey.com/industries/metals-and-mining/our-insights/succeeding-in-the-ai-supply-chain-revolution?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderate
- https://hbr.org/2022/11/how-walmart-automated-supplier-negotiations?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderate
- https://www.forbes.com/sites/blakemorgan/2018/09/17/5-examples-of-how-ai-can-be-used-across-the-supply-chain/?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderate&sh=1a7ceac0342e
- https://about.ups.com/us/en/newsroom/press-releases/innovation-driven/ups-to-enhance-orion-with-continuous-delivery-route-optimization.html?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderatehttps://about.ups.com/us/en/newsroom/press-releases/innovation-driven/ups-to-enhance-orion-with-continuous-delivery-route-optimization.html
- https://www.theverge.com/2019/4/25/18516004/amazon-warehouse-fulfillment-centers-productivity-firing-terminations
- https://www.ibm.com/watson/empower-workforce-ai-full/
- https://d3.harvard.edu/platform-rctom/submission/jp-morgan-coin-a-banks-side-project-spells-disruption-for-the-legal-industry/?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderate
- https://www.businesswire.com/news/home/20220112005244/en/Headspace-Health-Announces-Acquisition-of-AI-Driven-Mental-Health-and-Wellness-Company-Sayana?ssp=1&darkschemeovr=0&setlang=en-XL&safesearch=moderate
Introducing Forestry: A Logging Framework by Cleevio
Let us introduce Forestry - a GitHub repository - the very first open-source logging framework for Swift projects developed by Cleevio. By leveraging the power of open-source solutions, Forestry integrates most of the market-leading cloud logging services, providing developers with a versatile logging tool for their iOS projects.
Supporting open-source
At Cleevio, we believe that open-source solutions can be beneficial for everyone. By making software code publicly available, everyone can harness the power of collaboration and innovation to create better, more reliable solutions.
With open-source software, you are not limited to a single development team or organization. Instead, you can benefit from the collective intelligence of a diverse, global community of developers, all working together to create something great. Who would not support that?!
By creating our own open-source project, we hope to show that we're committed to quality, innovation, and engagement. Ultimately by embracing open-source solutions, we're not just creating better software. We are building stronger communities and driving progress in the tech industry. Giving back to the community is important to us, as we ourselves rely on several open-sourced libraries.
Meet Forestry
Our team envisioned a versatile logging framework for iOS projects that could easily cater to specific logging needs. We aimed to facilitate seamless switching between logging services without disrupting the existing codebase.
Forestry integrates most of the market-leading cloud logging services. To name a few, we support Datadog, Sentry, and Logrocket. Written entirely in Swift, it uses SPM for dependency management and is licensed under the MIT license.
We focused on making the library easily extensible so that anyone can add integration with their preferred logging service fast and be production-ready in just a few hours.
A typical workflow with Forestry involves using console logging for development, a cloud logging solution like Datadog for QA testing, and finally, using Sentry for error logging in production. This enables our team to quickly debug all issues without spending time integrating these tools.
The mentioned workflow will be implemented as follows:
You can always expand the functionality by creating your own logging service by conforming to the LoggerService protocol. ForestryLoggerLibrary documentation
Also! Everyone can rest easy, we have covered the whole ForestryLoggerLibrary with tests, so we are sure every event is delivered.
Conclusion
If you're looking for a powerful and user-friendly logging tool for not only iOS projects, Forestry is a fantastic choice. With its straightforward setup and smooth transition between logging services, Forestry is an easy-to-use solution that can significantly enhance your logging capabilities. What's more, its extensible architecture allows developers to add new logging services quickly, saving them time and effort.
We're always looking to improve, so If you manage to try it - please take a moment to share your feedback with us.
State of the AI Community: Exploring Ethics, Impact, and Applications
As a company that strongly believes in the importance of community building, we were thrilled to have the opportunity to showcase and discuss some of the most exciting developments in this field. The AI community is a vibrant and dynamic group of researchers, developers, and enthusiasts dedicated to pushing the boundaries of what is possible with AI.
In-person discussions within the AI community have been focused on three main themes that have generated significant interest and engagement online in recent months. These themes include the ethics of AI, the impact of AI on the labor market, and the practical applications of this powerful tool in real-world settings.
The potential of AI in a Wide Range of Applications
What makes AI so special is its ability to understand the nuances of language and generate contextually appropriate responses. This technology is increasingly being used in a wide range of applications, such as chatbots and virtual assistants, making our interactions with technology more seamless and natural.
“OpenAI and AI, in general, have the potential to be powerful tools and great assistants in tackling some of the most pressing challenges facing our world today, varying from healthcare to automotive. These technologies are transforming industries, unlocking new opportunities for growth and development and positively impacting human lives.” - David Zadražil, CTO at Cleevio
Addressing Ethical Concerns in AI Development and Use
It is important to recognize that AI is not without its challenges, and the community noticed that. One of the most significant challenges is ensuring that AI is developed and used ethically. There is a growing awareness of the potential risks caused by AI, such as perpetuating bias, data vulnerability, or AI being used for malicious purposes.
According to AI statistics, 52% of consumers do not believe AI will protect their private information. (Blumberg Capital)
The community discussed the need for transparency, which is currently offered scarcely in learning data and training models. This could help to minimize harmful speech, usually referred to as one of the issues. Resulting in the need for ethical guidelines and frameworks to ensure that AI is used responsibly and beneficially.
And they are not the only ones mentioning some form of proper research and regulation. An open letter has been signed by several prominent AI researchers — and Elon Musk — urging AI labs worldwide to halt the advancement of large-scale AI systems. The signatories argue that such software carries significant dangers to humanity and society. Appealing that caution is necessary. Signatories include Apple co-founder Steve Wozniak, Skype co-founder Jaan Tallinn, and a number of well-known AI researchers and CEOs.
AIs Impact on the Labor Market
One of the mentioned key effects of AI on society is the change in the labor market - especially in job roles that involve repetitive and routine tasks. With the development of AI technologies such as ChatGPT, which can automate customer service interactions and generate content, some jobs may become redundant, while new roles that require skills such as data analysis and machine learning will be created. Administrative workers are expected to be most affected, compared to the “little effect” seen on physically demanding or outdoor occupations, such as construction and repair work.
50% of the consumers believe people are already losing jobs and are being replaced by computers. (Blumberg Capital)
The rise of AI is also changing the way people work, with many companies adopting remote working models and leveraging AI tools to improve collaboration and productivity. As the field of AI continues to evolve, individuals and organizations need to adapt and upskill to remain relevant in the changing job market, from which 85 million jobs will be eliminated and 97 million new ones created thanks to AI by 2025. That’s an overall addition of 12 million jobs. (World Economic Forum)
Conclusion
That being said, we believe the AI community is and will remain a driving force behind some of the most exciting developments today. To stay relevant and competitive, we would suggest curiosity above everything else. With AI becoming more integrated into our daily lives, we must continue to develop and use this technology smartly and responsibly. As we continue to explore the possibilities of AI, we have the potential to transform our businesses in ways we never thought possible.
If you want to attend the next community event focused on AI, follow us on social media and stay tuned for more.
Data and statistics found in the article can be found in Blumberg Capitals 2022 AI Survey.
The Not So Equivalent Code: Demystifying Async Publisher
Working in agency development provides the benefit of frequently starting new projects, allowing us to start fresh - with a clean slate.
It means we can take advantage of new APIs provided by Apple without worrying about supporting older iOS versions with legacy code. We can also build upon what worked well in previous projects while eliminating any previous shortcomings.
For instance, in our most recent projects, we incorporated Swift's modern concurrency, which significantly streamlined the code in our application. It resulted in easy-to-follow code and reduced the likelihood of errors compared to similar projects that used Combine.
Using Modern Concurrency and one thoughtful comment in a code review from my colleague helped me realize a lot about the obvious - a behavior of AsyncSequence1, as well as the safety issues AsyncPublisher poses.
It all started with a test
Code written with async await. The next step was to write a test for its functionality. Since the test involved observing a @Published property in a SignInViewModel, my initial instinct was to utilize Combine. One of the resulting tests took the following form. Implementation details of SignInViewModel are beyond the scope of this article. Its primary function involves validating the inputs (email and password) when certain conditions are met. In this instance, the error is shown under the text field when it stops being the first responder.
The test passed, and I was happy and submitted it as a part of a merge request with other sign-in functionality and tests.
During the code review, a colleague suggested using async-await in the test instead of Combine. We briefly discussed it, and both believed the result would be equivalent. The idea led me down a rabbit hole that took me some time to navigate. The rewritten tests using Swift’s for await loop were failing randomly. It made me question the validity of my code and the implementation details of the SignInViewModel. When I looked into the details, the failure was caused by a timeout – there was a different amount of received values than expected. As I debugged the code, I discovered that observing viewError in the for-await loop resulted in various counts of the received values. I discovered that the behavior of AsyncSequence was different from what I had expected, despite reading various books, articles, and documentation.
Let’s put rubber boots on and start digging.
The first dig: Comparing AsyncPublisher vs subscribing via Combine
I will leave SignInViewModel for the rest of this article. Let us start with something simple and continuously increase the complexity to learn what is happening here; why the tests were failing and why they did so randomly. Let us leave the documentation behind, observe their behavior and devise the reasoning once we get there.
Let us first start with preparing a publisher. PasshthroughSubject should be a good candidate for this:
And let us observe it with basic sink in Combine and via for await loop, and print the received value.
There is no observable content, so let us send something through the pipe:
Now, if you look into the console, you will see lots of printed results– and if you look deep into the prints, most probably will be the same amount of prints from both sources – AsyncPublisher being the same as a basic sink.
So, why was it failing the test and not here? I got the notion of what is happening based on the initializer on AsyncStream. The initializer looks like this:
What caught my attention is the bufferingPolicy parameter, which decides how to buffer unused sequence items – whether they should stay there (and be buffered) or go. Let us test this assumption that the difference of for-await loop and sink would be noticeable when we introduce some delay with some heavy workload – such as finding the nth prime number in form of calling primeCount(100)2.
After introducing the delay, we finally have a minimum observable example of the issue. As you can see, the number of prints no longer corresponds - some numbers in the for-await loop are skipped, resulting in varying results across runs. It's worth noting that the highest number in the async for loop often ends in numbers other than 99, such as 97, which is the last number processed correctly.
Why does the for-await loop behave like this? It likely uses a buffering policy that discards some elements that aren't immediately consumed. While the exact buffering policy setting isn't crucial to this investigation, as you will see in a section about AsyncStream, it buffers a lot.
However, what's most important is how the for-await loop works. It only continues the iteration after the closure of the current iteration is over, ensuring that the for loop iterates synchronously while getting the items in a sequence asynchronously.
Counting differences
While it is interesting to see the number of prints varies, it still requires us to look at the code and try to guesswork. Let us prepare a counter to have a more reliable representation of results. I made the counter using an actor that takes a type as a parameter so that we can have a clear console:
The implementation is as follows:
As you can see, after every call to addToCount() is made, the counter increases by one and the count of the type is printed out, which means that the last print of a given type will be the relevant one for us.
Let us test it and see the results, first by instantiating the counters and using them inside our existing code (in Combine fashion, we have to create a Task to call asynchronous function):
Now we can finally see in numbers how much has been lost. The Combine counter’s last print is 100. For async, it is 83. Therefore, 17 % have been lost on my M1 Max without optimizations.
Making for await loop of AsyncPublisher work
We now have established a baseline and a test environment. We have observed that Combine works without any issues. Now let's focus on fixing the for-await loop to obtain the desired results.
Fortunately, the fix is straightforward. We need to create a Task and handle the for-await loop asynchronously without waiting. Doing so will cause us to lose the benefits of sequential code execution that Modern Concurrency provides. However, it will fix the issue that we have been dealing with.
This solution works because creating a Task is not a computationally expensive action that would cause us to lose an integer. Under normal circumstances, this approach should work well.
AsyncPublisher is not safe
In the previous section, we got to a point in which everything worked the way we desired – by asynchronously processing the items in the sequence, we were getting the same results from observing the for-await loop as with the Combine. Does this mean we can safely use AsyncPublisher without worrying about losing inputs? Unfortunately, no.
All it takes is to send a value concurrently, and we will be back where we started. For instance, in my working environment, after the following code was executed, the counter in Combine was at 1000, on async with 695. Not great.
Observing with a for-await loop is unfortunately not secure and can lead to data loss. Depending on the situation, there may be some ways to mitigate this issue. For example, if we know how many items we will receive, we can use collect() on the publisher. However, I do not see any good way to make the for-await loop work in the same way as subscribing to the publisher in Combine, where we can always handle it through async code. I have tried several other options, such as creating an AsyncIterator out of AsyncPublisher, but that did not yield any positive results.
These limitations are inherent to the for-await loop, as it only works on one thread and does not make any guarantees. However, we can leverage this limitation to our advantage in certain use cases, particularly when using it with AsyncSequence - or its implementation, AsyncStream.
AsyncStream to the rescue
AsyncStream is a built-in implementation of AsyncSequence in an asynchronous context. It allows awaiting its results in a sequence as well as allows publishing it (yield in async terminology) to sequence at any time with its continuation.
It is very easy to instantiate it, for our purposes, we can do something like this:
As you can see, I am storing the asyncStream in a variable for us to use later in the code, as well as storing the continuation. Although we unsafely unwrap the variables, the code is safe because AsyncStream returns the continuation in its init immediately (the provided closure does not escape the current scope).
Observing the AsyncStream is simple – we just need to make a simple change in our for-await loop. Since AsyncStream is an AsyncSequence, we can iterate it directly, just like any other Collection (such as Array). The only difference is that we do it asynchronously.
Continuing with our example, here's how we would yield the integers to the continuation:
With AsyncStream, the counter gets to 100 every time. The same applies when we count to 1000 with the code we already used. Not an integer gets wasted.
We no longer have to even process the items asynchronously, so we can simplify the observing code to just:
And why is it that AsyncStream works? It is because of its buffering policy - which is defined in its initialization. By default, the policy is unbounded, meaning every integer gets buffered regardless of how long it takes to process a single iteration.
We could very well destroy the ability of our AsyncStream if we wanted. For example, if we initialized AsyncStream with bufferingPolicy: .bufferingNewest(1), the counter would show only 2 instead of 1000. It supports the hypothesis that AsyncPublisher has a buffering policy, possibly a substantial one, but we still need to understand its limits for situations where we need it.
AsyncStream is a hero in our story because it allows us to set the buffering policy to fit our needs and expectations. It enables us to observe asynchronous values in an asynchronous context.
But what if we needed to observe a Combine publisher?
The question is: How do we asynchronously observe a Combine publisher? As I showed you earlier, we can achieve this by simply calling Task {} in the sink of the subscriber. However, this method doesn't allow us to use the ordered processing of the items that a for-await loop does.
If we create our own publisher, my recommendation is to use AsyncStream instead of Combine publishers, as long as we don't need to use reactive magic for other parts of the code.
If we cannot create our own AsyncStream or we want to observe a publisher we did not create, we can always create an AsyncStream, subscribe to the publisher, and yield the values to the AsyncStream.
And – to speak less abstractly – I think this may be a nice way to signify the differences between observing a stream in a for-await loop and awaiting the results and observing in Combine with sink in showing the information messages in the application.
Let’s say we have a following function from which we show the infoBar:
If we observe the publisher in Combine, we get the following result. As you can see, the messages get shown over each other - not the greatest behavior.
But we can always do it from AsyncStream and await the result of the completion via withCheckedContinuation, like this:
And the result is a readable message that is shown one after the other. We get the behavior we want without any difficulties. And what is best, we can use Modern Concurrency, so the code is quite readable.
Final Thoughts
Incomplete documentation is the cause of our limited understanding of Swift's Modern Concurrency, leaving us with much still to learn. As a result, we can only presume and guess. While we could learn more by analyzing the source code, doing so may not be a good use of our time, and it may be difficult to grasp all the details just by looking at it.
Therefore, further investigation in this area is needed. I hope more people will delve deeper instead of only scratching the surface.
In the meantime, let's not rush into rewriting every bit of code in async-await without careful consideration. We should always check our assumptions to avoid introducing unnecessary bugs.
1 In essence, AsyncPublisher enables observing any result from a publisher in an async for–await loop. You can find more in documentation https://developer.apple.com/documentation/combine/asyncpublisher
2 You can find a gist here: https://gist.github.com/lvalenta/07770221e7d653f6cfad6f2bda63af73 – It is just a random function a colleague found
Cleevio's Take on Creating Meaningful Client Relationships
Building a successful business partnership with your clients is essential in today’s competitive business environment. We believe it is necessary to create stable and lasting relationships with our clients that go beyond just sales. Here are some essentials we see as crucial in building business partnerships with our clients that go far beyond sales.
Listen and Understand
Listening to our clients and understanding their needs is fundamental to forming a successful business partnership. As well as asking questions and being open to learning more about their business, challenges and goals. This not only helps in future business, as our insight is already deeper but also creates a lasting bond.
Personality Matters
Take the time to get to know your clients on a personal level. Ask questions not only about their business goals and objectives but hobbies, interests and families as well. And really listen to their answers, as you never know who likes drone racing or goes to the same gym as you. This helps us develop a deeper understanding of our client’s needs and creates strong relationships.
Offer Extra Value
Once we have a better understanding of our client’s needs, it is time to start offering them tailored solutions to help them meet their goals. We believe in providing services that go beyond what our clients are expecting. Showing that we’re willing to go above and beyond helps us stand out from the competition and create a strong bond between us and our clients.
Build Trust
Trust is key to any successful business partnership. We are honest and open with our clients and make sure to deliver on our promises. This helps us build two-sided relationships with our clients, allowing us to communicate openly and freely.
Value Input
We facilitate product feedback through various channels i.e. data analytics or user feedback during live sessions. We sit down with our clients, go through relevant data, then combine it with the client's domain expertise and at the end, plan together what to build next.
By following these practices, we were able to build successful business partnerships with our clients that go far beyond sales and help us grow.
If you are interested in discovering how we approach our business partners, do not hesitate to get in touch.
Cleevio Rebranding: Why We Decided To Change
Today, we’re updating our website and brand to better reflect what we stand for at Cleevio. And even more importantly, what we can do for our clients.
Why
Cleevio always has big plans and aspirations. From building excellent digital products to creating a great place to work. As we evolved, the change was needed at last - not only in the brand but also in our services, which are now oriented towards long-term partnerships and focusing on the best value we can bring.
This growth, combined with the opening of our new office, meant that our website and branding no longer represented all the things we are doing and stand for.
Defining Cleevio
As it turns out, everybody at Cleevio had their preferences about how we should present the company. This creates a tangled web of powerful opinions on visuals. But these can be untangled – if you take a step back. To tell our story to the world, we first need to sit down and define it for ourselves. For that, we partnered up with Lukáš Burkoň, the leader of our new division, Cleevio Growth.
We conducted a workshop series on value propositions, customer profiles, and internal goals (just like we use with our clients, but for our own company!). With everybody on the same page, we achieved alignment across the company on the values and goals we should represent. Using the StoryBrand and brand archetypes frameworks, we crafted our tone of voice and brand personality: Creative Sage. Inspirational, guiding, articulate and knowledgeable.
Going Visual
How do you translate “Creative Sage” into a visual identity that can be used across a multitude of media and platforms? After all, these are two personalities that don’t necessarily match together on first look. We simply broke down what each could mean and represent.
- Sage: wise, minimalistic, lightweight, subdued, sharp, professional
- Creative: engaging, playful, inspiring, collaborative, a bit funky
Then it just meant iterating over your usual visual brand components like typography, colors, imagery, layouts and supporting elements.
Explaining What We Do
In addition to having design and engineering hard skills, Cleevio also strives to partner up with clients on the product side of their business. In the end, that means creating the best digital products with the most impact. For that, we need to explain the value we bring to the table.
Even the most powerful idea is fragile at first. However, with our 360 process, we can carefully capture it, mold it, and turn it into a successful statement of the client’s vision. Validate, prototype, test, iterate and develop. An excellent product is born.
We tapped into the 3D skills of one of our talented designers, Adam Kozel, to bring this to life. The idea and product are represented by glass structures, while our battle-tested process is visualized by solid black metal framing. On top of that, we use vibrant cursors to show the collaboration between us and the client – a key concept in every product we build.
Looking Into The Future
Launching our updated brand means a lot to us. It is as much a snapshot of where Cleevio is today as it is new ground for us to build on. Most importantly, it gives us a solid foundation to continue building true product partnerships with our clients.