Our blog

Fostering collaboration
through knowledge-sharing

Illustration of expert content creation for the [Your Company Name] blog, featuring articles on software development and technology insights.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Our Blog

Insights, stories, and experiments from our team.

How We Make Decisions Without Managers

We don’t have traditional managers. This is how we make decisions and keep things moving.

·

Mar 13, 2026

·

12 min read

Read full article

There's a myth that in flat organizations, everyone decides on everything.

That's not how it works. At least not at Kaizen.

When people hear "no managers," they often picture one of two extremes: either total chaos where nobody is accountable, or endless meetings where 80 people vote on which coffee to buy. The reality is neither.

Not everyone decides on everything. Not everyone votes. What we do have is a clear set of decision-making methods that we choose based on context.

It depends on who's affected and how deep the impact goes

Before choosing how to decide, we ask ourselves a few questions:

  • Who is affected? A decision that only impacts one team doesn't need the whole company involved. A decision that affects everyone's daily work does.
  • How deep is the impact? Changing the office furniture is wide but shallow. Changing the salary model is deep and lasting.
  • Is it reversible? If we can easily undo it, we can move fast and just inform. If it's hard to reverse, we slow down and include more people.
  • How urgent is it? And here we're careful to distinguish real urgency from anxiety, the pressure to decide quickly because someone already has "the answer" in mind.

These dimensions help us pick the right method. Not every decision deserves the same process.

Our decision-making toolkit

Over the years, we've landed on a few methods that we use depending on the situation:

1. Role-based decisions

Some decisions belong to a specific role. If someone owns a responsibility, say, office logistics or hiring for a team,  they decide within that domain. No committee needed. The key is that roles are transparent: everyone knows who owns what, and the scope of each role's authority is clear.

2. Advice Process

When a decision doesn't clearly belong to one role, or when it crosses boundaries, we use the advice process. Here's how it works:

  1. Someone takes the initiative. They identify the problem and own the process.
  2. They gather input from people who are affected and people with expertise.
  3. They seek advice, real conversations, not rubber-stamping.
  4. They make the decision and communicate it, including what advice they incorporated and what they didn't (and why).

The decision-maker is not a committee. It's one person (or a small group) who takes responsibility. But they don't decide in isolation, they bring in the perspectives that matter.

We sometimes call this "Team Advice" when a working group forms around an issue that doesn't naturally fall into anyone's area, and "Area Advice" when a team opens up a topic that exceeds their own scope.

3. Consent (not consensus)

Consent is not "everyone agrees." Consent means "no one has a strong enough objection to block this." We do use a poll, but not to count votes — we use a 1-to-5 scale to measure the level of agreement and surface objections, not to let the majority rule.

We use it in two flavors:

  • High-participation consent: For decisions with deep, company-wide impact. This is our most expensive and slowest method, which is exactly why we reserve it for high-impact decisions that affect many people. The Board sets the boundaries, for example, when we moved offices, they defined the monthly budget. Then a working group produced proposals, collected feedback, evolved them, and the whole company expressed their position for the final decision. Silence is not approval; we explicitly ask people to weigh in, even if it's just "I have no objection."
  • Lightweight consent: For decisions that are broad but not deep. Participation is optional, anyone who's interested can jump in. We share the proposal, open a window for objections, and if nobody opposes, we move forward. This gives us speed without sacrificing transparency. If nobody engages, that's a signal too, maybe the proposal doesn't add enough value, or we're using the wrong channel.

4. Inform, don't fake-consult

Not everything needs participation. When a decision has already been made through a legitimate process, the right move is to inform, not to fake-consult. One of the fastest ways to kill self-management is to ask for feedback and then ignore it. If you're not going to change course based on input, don't ask for it, just be transparent about the decision and the reasons behind it.

What we explicitly avoid

  • Decision by Voting. In a company context, majority rule creates losers. And losers become detractors, often generating more resistance than an autocratic decision would have. Instead of voting, we prefer to evolve a proposal through feedback until it's "good enough for now," and then introduce a review point to adjust later. If voting happens at all, it's the cherry on top, not the main course.
  • The "surprise" approach. Working behind closed doors and then unveiling a finished decision is a recipe for frustration. Adults don't need surprises. Adults need to feel like they're part of the process. The complaints that follow a surprise aren't about the decision itself, they're about not being included.

Why we work this way

We didn't adopt these methods because they're trendy. We adopted them because they solve real problems:

  • Better decisions. When you include affected people, you get information you wouldn't have had otherwise. Ideas emerge that no single person would have come up with alone.
  • Less resistance. A person who feels heard is far less likely to resist a decision, even one they wouldn't have made themselves.
  • Faster execution. It sounds counterintuitive, but participative decisions often execute faster because people already understand and support them. The time you "save" by deciding alone, you spend later managing pushback.
  • Distributed authority. When people can make decisions within their domain without escalating everything to a founder, the organization scales. The bottleneck disappears.
  • Resilience. If a shared decision fails, the group adjusts together. If a top-down decision fails, the blame falls on one person and the chances of proactive correction drop.

The real principle behind all of this

Transparency is the foundation. Every method we use, from role-based decisions to high-participation consent, works because information flows openly. People know what's being decided, who's deciding it, and how they can participate.

Horizontal doesn't mean structureless. It means fewer hierarchical levels, clearer roles, and intentional decision-making processes that match the weight of each decision.

Not everyone decides on everything. But everyone knows how things get decided.

·

April 30, 2026

How We Make Decisions Without Managers

We don’t have traditional managers. This is how we make decisions and keep things moving.

12 min read

Read more
00
articles
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

12 read time

Read more

With a commercial office in Boston, U.S., and the headquarters in Uruguay, South America, Kaizen Softworks is a software development company with a focus on product development from scratch.

At Kaizen, professionals create, develop, and deliver customized software by establishing an effective collaboration in which the success of the business relationship is most important. They create a pillar of trust, transparency, and flexibility; these are the building bricks of the solid and consistent partnership Kaizen offers.

Since the inception of Kaizen Softworks, they have been producing custom applications and have gained extensive experience in developing robust solutions for a wide range of domains. They offer consultancy services in the full cycle of creating software. From research and design, to programming, QA and testing, maintenance and enhancements.

GoodFirms is an online review portal that evaluates various businesses registered with it to receive daily accreditation. The valuation is based on three criteria - Quality, Reliability, and Ability. Similarly, GoodFirms also valued Kaizen Softworks and found it as a leading mobile app development service provider in Boston amongst the listed ones. It also claimed that Kaizen had risen to the top of GoodFirms companies for software development and web design in Uruguay and Massachusetts, respectively.

Thus, providing ever-improving mobile app development services, Kaizen Softworks thrives as one of Boston's best mobile app development company at GoodFirms.

About the Author

Working as a Content Writer at GoodFirms, Anna Stark bridges the gap between service seekers and service providers. Anna's dominant role lingers to form every company's achievement and critical attributes into words. She strongly believes in the charm of words and equips new approaches that work, always with concepts, something new to create, and something original to define the firm's identity.

12 read time

Read more

Kaizen Softworks has been recognized as one of the top ranked Software Development Companies in 2021 by DesignRush. Among the different services offered, we were recognized in the following categories.

Enterprise Software Development Companies. Whether our clients are dealing with a new product inception, legacy systems maintenance and migration, process automation, new features implementation or API integrations, our solutions are purpose-built to assist their processes in a productive and rapid way. Understanding their business goals and the right problems are key to meeting specific requirements at a competitive cost to build, maintain and modify software solutions, helping our clients to gain independence, scalability and achieve lower integration costs.

Software Testing Companies. We have strong workflow processes in place to ensure the operational efficiency and productivity of different solutions. With cutting-edge technologies and the latest resources, we help our clients  to properly maintain their solution and perform regular quality assurance services such as performance and error monitoring. Through this ongoing work, we will consistently bring and deliver new solutions onto the table to help our clients to stay competitive in an always evolving market.

.Net Development Companies. From front end work to back end and database coding, our .NET developers are capable of adding immediate value and capacity with the flexibility and availability to fill short-term positions.

Nearshore Software Development Companies. When projects require a little extra expertise, we are able to add professional resources. We respond to changes as they occur and take immediate action and our clients know it. We are committed to work as partners with our clients in order to create new strategies without the high risk costs associated with in-house development. While conversion rates from the U.S. dollar to our local currency are favorable, the real value comes from our passion and eagerness to transform your ideas into quality work.

Special congratulations to our team, who are always challenging assumptions and bringing innovative ways of thinking onto the table. We live and breathe what we do. Amazing things can happen when our team are great people who truly enjoy our work, taking pride in learning how to give our best.

We'd love to learn about your software development needs

GET IN TOUCH

12 read time

Read more

Hello there, our valued friends, clients, and everyone who's been a part of our amazing journey! We're absolutely thrilled to share some truly fantastic news with you. Kaizen Softworks has earned its place as one of Clutch.co's top Software Development Companies in the United States for the year 2020. For those not familiar with Clutch, it's a B2B platform renowned for providing ratings and reviews for top IT and software companies. 🎉

Clutch Badge of Top B2B Companies in the United States

This recognition is more than just an accolade; it's a testament to the incredible dedication and hard work of our entire team. It's a reflection of the mission we set out on six years ago. Back then, our mission was simple but powerful: we wanted to step into our clients' shoes, deeply understand their needs and aspirations, and then go that extra mile to help them achieve their goals.

As we look back on our journey, it's truly heartwarming to see how that early-stage mission has evolved and become an integral part of our company culture. Yes, we've grown as a company, but the most remarkable growth has been that of our clients. It's a profound joy for us to witness the success and progress they've made with our support.

However, it's essential to remember that none of this would have been possible without our incredible team. They are the backbone of our operation. Their remarkable talents, unwavering focus, and unparalleled commitment are the driving forces that have shaped Kaizen Softworks.

So, what's next? We're filled with anticipation about the path ahead. We can't wait to see how this recognition propels us into the future. We're committed to pushing the boundaries, continuing to support our clients and partners, and striving for even greater heights.

Our journey is just beginning, and we're elated to have each and every one of you join us on this incredible ride. We're deeply grateful for your unwavering trust in us and for being an integral part of this exciting adventure.

Check out our Clutch profile here: https://clutch.co/profile/kaizen-softworks

·

Sep 22, 2020

Improve Site Speed and Loading Times for Better SEO Rankings

Slow sites hurt more than just UX. This is how we approach performance and SEO together.

12 read time

Read more

Across the internet today, we can find websites with many different types of features: sliders, videos, images, animations, and more that make them attractive to end users. However, all of these features can have a negative impact on one major factor: performance.

But wait, why should I care?

According to DoubleClick by Google, 53% of mobile site visits were abandoned if a page took longer than 3 seconds to load. Also, it was found that sites loading within 5 seconds had 35% lower bounce rates, 70% longer sessions, and 25% higher ad viewability than sites taking nearly four times longer at 19 seconds.

The performance impact can be measured in revenue too. DoubleClick found publishers whose sites loaded within five seconds earned up to twice as much ad revenue as sites loading within 19 seconds.

So you should care, and a lot. Performance can be the one thing that is making users ignore your website. It plays a major role when it comes to retaining users, user experience, and revenue. It also affects Google Rankings. That means performance is taken into account by Google when positioning your website in the search results higher (or lower) than your competitors.

So, how can we improve it?

Removing Render and Parsing Blocking Resources

A browser’s rendering engine is in charge of displaying what you see on the screen. In order to accomplish this, it has to parse HTML and create a DOM tree with all the existing HTML elements, render tree construction combining CSS attributes and the DOM tree, figure out each element’s position (layout process), and then paint the page.

When rendering a page, the rendering engine considers CSS as render blocking resources and scripts as render and parsing blocking resources.

That means that, by default, the page won’t be painted until the CSS and javascript are loaded, parsed, and executed. That presents a problem if your website has lots of CSS and javascript blocking parsing and rendering on your website, since performance can be affected dramatically and the site will take a long time to load.

Loading your website resources at the right time is essential to improving your website performance. If you load resources that avoid blocking parsing and rendering, your site will display much faster and the lesser critical content can be loaded in the background while the user interacts with the page. There are several ways to do this:

Using media print and onload=’this.media=’all’ to load non critical CSS (or loadCSS as an alternative)

Loading CSS with media type ‘print’ will tell the browser that the resource is not important because the media type doesn’t match the current environment (screen), and will load the stylesheet asynchronously without blocking page rendering.

<link rel="stylesheet” href="style.css" media=”print” onload=”this.media=’all’”>  

loadCSS is a popular library that also makes this possible.

<head>  
   <script id="loadcss">
     // load a CSS file just before the script element containing this code
     loadCSS( "path/to/mystylesheet.css", document.getElementById("loadcss") );
   </script>
</head>  

We also can combine this with ‘rel=preload’ (in supported browsers) if we want non critical CSS to be loaded as soon as possible.

<link rel="preload" href="style.css" as="style">  

This approach has a major downfall if applied to all CSS on the page: the browser will show a Flash of Unstyled Content (FOUC) before loading the CSS. This means that some essential CSS needs to block page rendering in order for the page to be displayed with its proper, critical styles. But asynchronously loading the remaining styles is a must for improving performance.

Efficiently loading JavaScript with defer and async

In order to load javascript efficiently without blocking HTML parsing, it’s very important that the scripts are placed in the right position. If placed in the header with no async or defer attributes, a lot of delay will occur because the browser will have to load and execute the script before continuing with HTML parsing and rendering. In order to avoid this, a common practice is to place the script tags before the  tag. However, async and defer are better approaches:

Async is a boolean attribute that you can place in a script tag that allows the browser to load the script in the background while it keeps parsing the HTML, and then execute the script as soon as it is loaded. This blocks the parsing if it happens before the browser finishes parsing. Async scripts are executed in random order as they become available.

Defer is also a boolean attribute that you can place in a script tag that allows the browser to load the script in the background while it keeps parsing the HTML. It then executes the script after the parsing is done. It’s similar to placing the script at the bottom of the page, the only difference being that it’s loaded in parallel while the HTML is parsing content. It also allows you to execute all deferred scripts in the order in which they appear on the document.

Note that both of these attributes are only useful if the scripts are declared in the header, otherwise they won’t do anything.

Comparing both attributes, async may block html parsing but defer guarantees not to. Neither of them guarantee anything on blocking rendering (however that can be done with the onLoad event).

Furthermore, their biggest difference is the execution order. Async scripts are executed in a random order as they become available, while deferred scripts are executed in the order of their appearance.

I recommend to use async loading in third party scripts where the loading order isn’t important (i.e. Google global site tag) and defer loading for scripts that need the whole DOM loaded and/or their relative execution order is important.

Comparing script loading performance, we obtain these results:

Image of a Scripting, featuring HTML code

These techniques (along with image lazy loading which is a critical performance improvement that we will comment on in a future post) were implemented on our site in order to improve its performance.

For comparison, the performance of the site’s old and new versions was measured locally using Lighthouse version 6. In the results shown below, we see a clear improvement in performance with the first contentful paint rendering almost four times faster in the newer version and the largest contentful paint rendering almost six times faster.

Mobile Version

Old Sit

SEO analysis dashboard, offering critical insights for effective search engine optimization strategies and performance tracking.'

New Site

SEO analysis dashboard, presenting essential information for enhancing website performance and search engine rankings.

Desktop Version

Old Site

SEO analysis dashboard, providing valuable data and metrics for optimizing online performance and search visibility

New Site

SEO analysis dashboard, displaying comprehensive data and insights for search engine optimization evaluation and strategy

Bibliography

12 read time

Read more

Why Outsourcing?

Outsourcing is a powerful weapon, but if you don’t know how to harness its power, it might end up backfiring.

Offshoring or nearshoring software development tasks could prove very profitable for your organization and professionally enriching. We believe that anyone should be able to get the most out of an outsourcing experience.

Thus, in this post series we will be helping you understand whether to offshore or nearshore software development, with whom, and how. Armed with this knowledge, you’ll be able to make an educated decision on whether to embark on this journey.

In this first part, we will explain the most common risks and rewards associated with outsourcing, define what SMART objectives look like, and understand expectation versus reality so you can check if outsourcing is what you need to achieve your goals today.

Risks and Rewards

Does outsourcing seem like an appropriate technique for addressing your personal goals and professional objectives?

Chances are that if you survey your organization, you will find that some people say that outsourcing steals jobs and destroys organizational culture. Others might say that it could help the company stay in business and beat the competition.

Each side has valid points. Rather than debating, let’s explore some of the risks and rewards of outsourcing to see if it could work for you.

Risk types

Starting with the negatives, we can classify risks into three categories: external, internal, and personal.

External

External risks are related to factors outside your organization’s control. These include: geopolitical instability, intellectual property loss, inadequate vendor capabilities, and failure to meet joint responsibilities.

One of the most dramatic scenarios could involve a terrorist attack in “safe” offshore destinations like Mumbai or Moscow, which underscores the importance of understanding different countries’ political stability.

A less dramatic example would be when an unexpected change in tax regulation at an offshore location suddenly jeopardizes your investment.

Your potential partner’s financial stability, organizational maturity, technical skills, and ability to acquire and retain qualified talent are key to fully understand the situation you are getting into.

Internal

Internal risks are associated with factors your organization can control. The most notable ones include: unrealistic expectations, lack of organizational preparation, and negative staff impact.

Sometimes even the expectation of outsourcing, if incorrectly managed, can create organizational adversity by declining employees’ morale and productivity. Also, outsourcing initiatives will likely imply some degree of changes for existing processes and roles.

Maybe the most important internal challenge will lie in the unrealistic expectations that some organizations set about the end result. Exceptionally high-cost reduction expectations are one of the most common reasons for dissatisfaction.

Personal

Outsourcing can affect you personally in many ways, introducing changes to your lifestyle, career, and reputation.

Outsourcing may require you to increase the percentage of time you spend on activities you don’t enjoy or to shift working hours to cope with different time zones.

The very nature of outsourcing means that someone else does the work. In many cases, this will be someone whom you have little control over, but it is your name that will be in the line.

Moving from the role of individual contributor to representing an offshore or nearshore team might mean becoming a bearer of bad news. And that will have an inevitable impact on your reputation.

Reward types

With all the risks listed above, why would anyone want to outsource abroad anyways?

The answer is that competition is hard, the market is demanding and outsourcing could give your company a competitive edge. We can divide outsourcing benefits into organizational and personal ones:

Organizational

Cheaper salaries, a strong exchange rate between the US dollar and almost any other currency, lower overhead, economies of scale, controlled operation costs, productivity, and quality improvements all contribute to increased profit through resource efficiency and savings.

At the same time, outsourcing allows you to reallocate the workload during your busy season and shift less critical services abroad. This will help you meet deadlines faster and focus on disruptive innovation projects to gain a competitive advantage.

Outsourcing broadens your recruiting horizons. Having access to a huge staffing pool gives you access to hard-to-find personnel and the opportunity to team up with international experts. In addition, many outsourcing providers have a tremendous work ethic and drive to succeed.

A shortened time-to-market can be achieved as well. Having access to specialized skill sets, unique expertise, and certified processes can improve your competitive advantage.

Personal

There are several key personal benefits to choosing an international team.

From your career’s perspective, consider running an outsourcing engagement as a productive training session for developing management and leadership abilities. These are skills you can add to your resume and you would be surprised how often recruiters and companies look for outsourcing management abilities.

The skills you develop like negotiating, learning foreign languages, managing remote teams’ day-to-day, and assertiveness are invaluable skills that will benefit you in the long run. Accomplishing successful outsourcing engagements could catapult your career forward and open new doors.

Let’s not forget traveling! Seeing new places, meeting new and interesting people, experiencing foreign cultures, and trying new cuisines without spending your own money are major perks.

Having discussed outsourcing risks and rewards, you now have a better picture of the potential it has. But before deciding whether it’s for you first let’s consider which objectives you want to accomplish through outsourcing.

Defining SMART Objectives

This might not be the first time you’ve asked yourself if you should outsource a project, an initiative, or a company function.

Each time you face this situation, always remind yourself: you should only offshore or nearshore either when it is the only tool you have at your disposal or when it is the best tool for the job.

Consequently, you will first have to understand and determine what the “job” is in the first place.
When determining the “job,” you shouldn’t settle for broad goals like “need to reduce cost” or “put local staff to better use”, since ambiguity and lack of specification are lethal to success.

Specify your goal applying the SMART business management technique

Graphic of SMART objectives

Defining SMART criteria objectives help you stay focused on your goal and make good decisions. For instance, let’s check this objective: “Outsource to substantially improve quality assurance (QA).”

What’s the goal here: to use outsourcing or to improve QA? What does “substantially” mean? How long should it take for improvement to occur? This objective is too vague, doesn’t guide you towards actionable steps, and generates more questions than answers.

Now, let’s compare it with this other objective: “Reduce my department’s budget expenditures by 20% next quarter by nearshoring the maintenance of a legacy asset while my in-house team develops a new one”.

This one appears to be SMART since it’s specific and measurable (20%), it defines an action (nearshoring the maintenance of an asset), it focuses on results (reduce my department’s budget expenditures), and it’s time-bound (next quarter).

Defining a SMART goal is the first step when deciding if it makes sense to outsource work. But first, you might want to compare some financial and practical considerations to avoid common mistakes.

Expectations Versus Reality

Offshore outsourcing has been called one of the greatest stories ever sold.

Like many products today, outsourcing comes with a lot of fine print. The pain for smaller companies is that they don’t have the bandwidth even to read it.

However, understanding the fine print is important in these three areas: cost savings, vendor’s ability to scale, and quality of deliverables. Let’s check them out.

Cost Savings

How much money can you save by outsourcing? On the surface, it seems obvious. Even with wage inflation in India, China, and Eastern Europe, rates there are still substantially lower than in the United States.

For example, a mid-level Java developer in San Francisco earns roughly $75 per hour, compared to $25 per hour on average in Bangalore, Shenzhen, or St. Petersburg. At first glance, this lower rate translates into savings of more than 65%, or a 3:1 ratio (for every on-site Java developer you can get three offshore Java developers).

Is it that simple? Will getting three developers for the price of one give you three times the productivity? Unfortunately, no.

Hiring cheaper offshore developers doesn’t mean they will be as productive as local ones. Due to productivity issues, the difference in hourly rates could not necessarily translate into overall cost savings.

Overhead

Overhead expenses related to management, communications, and risk mitigation can eat away what you save in low hourly rates.

For example, if you outsource a small QA team, for example, you’ll probably need both local and offshore QA leads. Without outsourcing, a single lead is enough.

Moreover, if you distribute teams across multiple time zones, language and culture differences could significantly increase the volume of communications required to minimize misunderstandings.

Turnover Ratio

This one is an important expense to keep in mind. Losing a tech team member can be very expensive — as much as three to twelve months of employee salary. The turnover costs come from loss of productivity, hiring fees, training ramp-up, and other factors.

The degree of turnover is typically measured by turnover ratio or the number of lost employees divided by the team size over the course of the engagement. For example, a loss of two developers from a team of ten over the course of the engagement would be a 20% turnover ratio.

Ability to Scale

Many organizations face the challenge of adding personnel for an increased workload and ramping down when demand reduces. Outsourcing seems to be the perfect solution to this problem. Yet some staffing issues are inevitable:

Finding staff with specific skills, especially for cutting-edge technology, can be extremely time-consuming even for a top-tier vendor.

In your search for qualified personnel, consider which country you are outsourcing to and how the government supports young IT professionals.

Quality of Deliverables

There is a strong perception in the industry that the quality of deliverables produced by offshore personnel is inferior to that of local staff.

This perception is deeply flawed because outsourcing partners can either deliver higher or lower quality products and services than those of local employees. The challenge in getting quality deliverables lies in understanding all the aspects of communicating quality expectations to your partners and overseeing their work.

Summary

In this first post of these series, we have brought you general info and insights on outsourcing to help you check whether outsourcing software development is what you need to accomplish your goals.

First you have to be aware of the risks and challenges that come along on this journey. Some of them are external and out of your control, while others are internal to your organization and can be directly dealt with.

Of course, there are plenty of rewards as well like cost reduction, shortening time-to-market, improving workforce usage, improving your management skills, traveling around the world, and increasing productivity and process agility.

Second, you have to ask yourself what your goal is and what you want to accomplish by outsourcing. Remember that ambiguity and lack of detail are lethal to success. Thus defining goals with SMART criteria will go a long way in helping you establish realistic and actionable objectives.

Last, don’t forget to compare expectation versus reality. You would be better off bringing inflated expectations down to earth and taking into account factors like overhead expenses, vendor turnover ratio, scalability, quality of deliverables, and cost-saving versus productivity.

In the next installment of this series, we will be talking about what, with whom, and how to offshore or nearshore software development so you can make an educated decision on whether to do it.

We hope this post has been useful! A special shout-out to Daniel Castro who collaborated in the creation of this post.

Bibliography

12 read time

Read more

React can be so simple and so powerful that it is one of the first choices when it comes to building a web app nowadays. But with great power comes great responsibility. Being so widespread and used, it's easy to find tons of results when looking for solutions that fulfill developer needs, but the most popular solution may not always be the best for every case.

In this article I’m going to cover some common patterns and tools developers tend to blindly stick to without assessing whether they actually apply to their specific use case or not.

Using a Library for State Management

Don’t get me wrong, correct state management is a fundamental part of building a reliable, scalable, and futureproof application. It’s particularly important to take it into account early on in our projects, but you might want to think twice before just starting with a template based off of  [insert popular state management library here]. There are a several reasons why I think this way:

  • It forces you to think and model your application in the library's way of doing things, instead of making choices that could reflect the business reality in a more accurate way. Whether you use redux or mobx (or nothing at all) should depend on if it makes sense for your use case, and not simply on what’s trendier.
Official State Library for React
  • You may be making your app less performant. Bundle sizes and performance on lower end devices are metrics that we as developers tend to gloss over, but can end up making a huge difference on the way your users interact with your product. Also, there’s more library code that when used incorrectly may lead to unwanted re-renders, thus making your app less responsive.
A graphic
  • At the end of the day, it’s something new you need to learn, document, teach, maintain, and upgrade over time. This is the key factor when deciding to use a state management library or not: will it save you enough time and make your life that much easier in the long run that it’s worth teaching it to every new developer that joins the project? Will you have the time to document a specific scenario where you do things differently? Are you willing to upgrade all of your codebase because of a breaking change? If the answer to all of these questions is yes, then go ahead.

Creating Too Many Files/Folders

If you come from a framework like angular, you may be familiar with the idea of creating a couple of files and a folder just to organize your independent UI components. Add modules, routing files, indexes, and services and you’ll end up with a lot of boilerplate to make things work the way you want in any given scenario. Boilerplate is not a bad thing per-se, but with React we’re not required to have this much ceremony in order to build our apps.

A computer screen with lines of code

Now, I’m not saying you should go and delete all of your .js files and bake everything in the same file, but embracing the flexibility the framework gives you will help you create apps that are easier to navigate through, and therefore, are more maintainable. The official React documentation even encourages this approach, and provides us with some guidelines to take into account when laying out our app structure.

Here are some things I do to avoid unnecessary nesting/file creation:

  • Don’t create boundaries where there are none: While it’s pretty common to  consider that everything apps are made of is screens and components, what actually differentiates one from another? What you think of today as a component may become a screen down the road, or vice versa. Whenever your domain makes it clear that some things should belong to a folder, then go for it. Creating an extra file folder before the need comes up just creates extra work. Dan Abramov talks more about this in this article where he clarifies the difference between presentational and container components—but beware! You’ll actually find a disclaimer where he talks about how his views have changed since the writing of that article.
  • Leverage the power of hooks: You may be tempted to create new files as new complex components start forming, and eventually you might want to put together components that share similar logic in a folder. The thing is, you may be able to avoid all of the added complexity of similar-yet-specific components by using hooks to properly reuse your logic.
  • Use Styled Components: Styled Components can help keep all the styling and the logic related to it within the same file most of the time. This depends greatly on each use case, but they’ve gained popularity because of their flexibility and simplicity to setup, read, and maintain across my apps.

Testing the Wrong Places

While a robust testing suite should be a priority whenever you ship a product that will continue being developed in the future, testing the wrong places could be the source of many frustrations and time wastes, especially on the frontend. Let’s first define what these “wrong places” are and aren’t.

Kent Dodds writes in How to know what to test

“When writing code, remember that you already have two users that you need to support: End users, and developer users. Again, if you think about the code rather than the use cases, it becomes dangerously natural to start testing implementation details. When you do that, your code now has a third user.”

In this post we’re talking about how to make the “developer users” happier. If you’re able to write tests that will actually detect bugs in the future, you’ll inevitably be happier. How do you achieve this? By testing your app the way the users would, avoiding high-effort/low-value code chunks, and writing concise and understandable tests.

Let’s break these down one by one:

  • Testing the way users would use the app: Here I strongly recommend reading Kent Dodds Testing Implementation Details, who elaborates on how testing implementation details can lead to error prone tests that aren’t actually very useful for catching bugs.
  • Avoid high-effort/low-value code chunks: If you’re solely using code coverage as your metric to determine the quality of tests (which has its own problems), you’ll often find there’s some code dependant on a third party library that doesn’t quite work as you expected and drags the coverage down. In this case you’ll have to weigh how critical the feature is to the application vs the amount of time you’ll have to spend coding, maintaining, and replicating the functionality across several sections of your app.
  • Write concise and understandable tests: The more simple, explicit, and understandable a test is can reflect how well a functionality is written. While you should avoid making your implementation more complex just to simplify the tests, if your test can describe what the end goal of a functional piece is, a new maintainer might find it easier to read and make changes to the codebase.

While there are no rules set in stone for writing perfect React code, following these guidelines has saved me time and spared me from bugs and unnecessary meetings in my career. I hope it does the same for you.

Do you have any examples of over-engineering in your favorite framework? How do you usually solve them? Leave it on the comments!

·

Jun 30, 2020

How to Choose a Nearshore Software Development Company?

Picking a nearshore partner isn’t trivial. These are the things we’d look for.

12 read time

Read more

There’s plenty of material telling you about the benefits of outsourcing software development services to nearshore companies. The upsides are similar time zone, cultural affinity, a high-quality talent pool, and cost reductions. Even though these things are true, that’s just a general idea of what nearshore outsourcing is all about.

You might be already interested in it, but given how many software development teams are out there, how do you know which one you should partner with?

Read on as we point out what factors are most important to consider when choosing your next nearshore software partner.

A bargain might compromise your business

A wooden piggy bank

If you’re considering nearshoring just to save as much money as possible, then you’re missing the point. In fact, just considering the cheapest option could lead to bad experiences.

Magne Jørgensen, researcher and professor at the University of Oslo, showed in a research paper that software providers with bids 25% lower than the average correlate to a 9% increase in the frequency of project failure for the same skill level, suggesting that an excessive emphasis on low prices makes it more likely that projects fail.

Software development is no simple task. It takes hard work, knowledge, skill, and most importantly time, to end up with a scalable, testable, and user-friendly software product ready to run.

Promises of exceptionally quick work at the lowest price should be viewed with healthy skepticism. You might know of folks in your community who have already gone through bad situations when their cheap outsourced software turned sour, like Boeing's offshore outsource fiasco.

Don’t get discouraged though!

Finding quality nearshore software development companies while not breaking the bank is still possible because of the exchange rate, salary differences, and great talent pool. You just need to take your time and correctly assess your potential partners before making a decision, which leads me to my next point.

Agile methodology is key to success

Avoid injecting money into a black box, only to open it months or years later and find something completely different than what you were expecting. Partnering with software companies with a strong agile approach is a great way to prevent this.

The Forbes Technology Council agrees that an agile software development process translates into quality project management: faster feedback cycles, effective problem identification, disrupting changes prevention, flexible prioritization, maintaining high customer satisfaction, identifying benefits sooner, free commitment and continuous improvement.

Software development does better in an ongoing back-and-forth process, where you describe your desired result to your IT partner, evaluate the intermediate results, both parties provide feedback and exchange opinions, and iterate the process until convergence is finally achieved.

And how do I identify a software company with a strong agile culture you ask? You should evaluate how they behave. Shy away from those trying to sell you pre-established solutions, and stick to those who are honestly trying to understand what your needs are and how your business model works.

A good agile team will not only come to the Scrum Ceremonies with regular updates, but they will dive deep into your ideas and actively look to suggest recommendations and improvements to your product.

Every project is unique, and will require the most focused, responsible, and committed development team to bring your ideas down to earth and successfully deliver. Checking references is a good starting point.

The importance of user experience (UX)

Nowadays our brains are being bombarded with information and stimulus coming from everywhere, specifically from our computers and cell phones, constantly distracting us with our social media feed, news updates, work info, and more.

Therefore, customers aren’t only needing, but are demanding, simple and easy-to-use UX/UI that lets them quickly understand and make use of your services, giving a necessary rest to their busy heads meanwhile.

To get an idea of how important this is, take for instance a research study by Baymard where they tracked the global average e-commerce cart abandonment rate for 9 years, concluding it was around 69%. The main reasons were UX/UI flaws at the design and check-out flow that frustrated or made it hard for users to buy.

If this wasn’t enough to make a point, suffice to say that after a no-ROI period, Walmart decided to redesign its website in 2018, paying special attention to UX/UI. The results: Walmart’s e-commerce sales grew by 43%.

The important question here is whether your software consultant can turn all those lines of code into something accessible and easy for your customers to use and love.

When searching for your next nearshore software development agency, take a look at their case studies. See if their previous projects not only do what they say but also look professional, simple, and smooth.

Don’t forget that even if you have the most solid software engine running, it's worthless if users find it counterintuitive.

Go for flexibility

Today's world moves fast. To survive, you must have the ability to quickly adapt to new situations.

What worked for you in the past might not be useful now. Committing to long-term relationships with a partner through hard-binding legal contracts might not be your best bet.

Outstanding nearshore digital transformation agencies know and embrace this. Moreover, they will offer flexible working frameworks where you can easily ramp up and down without any bureaucracy.

They will freely let you decide if you want to stay or leave because they’re committed to consistently providing you with the best service. That way you’ll want to keep choosing them as your software development partner because you continue to see ROI in the relationship. That’s the kind of value-based relationship you’re looking for!

Look for stable countries

So far we’ve talked about software companies and business, but given that nearshoring is the central topic of this post, we can’t avoid talking about countries.

Their strengths and weaknesses vary a lot from region to region, making it difficult to establish generalities. However, there are some key factors you should keep in mind when researching countries: political, economic, and judicial stability.

Usually, nearshore countries fall into the category of “developing countries”, which makes them interesting because of lower costs, but many often suffer from social upheavals, economic crises, and mismanaged governments.

Any of these issues can put your investment or business at risk because they could lead to exchange rate restrictions, massive layoffs, authoritarian governments, or expropriations.

When looking at which country to choose, consider Uruguay. This South American country is recognized worldwide for its enduring democratic institutions and solid rule of lay, high human development index, stable and open economy, excellent English level, the fastest internet connection in the region and massive tech education investment.

Summary

Key things to keep in mind when choosing which nearshore digital transformation agency to partner with:

  • Take advantage of natural nearshore lower costs and aim for quality providers rather than blindly going for the cheapest option available
  • Get close to development teams genuinely trying to understand what you need, instead of imposing their solutions. Value honest and involved development teams who aren’t afraid of telling what they think
  • Give special consideration to software companies with UX/UI expertise. You want your users to experience software that runs as good as it looks
  • Stick to firms that let you freely come and go within flexible working frameworks. They’ll sustain value-based relationships, providing ROI to you
  • Look for the most stable countries to invest in. Stay updated on news about political instability, economic crises, or social upheavals. This way you’ll avoid future pitfalls.

Looking for a true nearshore development partner?

GET IN TOUCH

12 read time

Read more

Nowadays, JavaScript is all over the place. As the code evolved, testing libraries and strategies like TDD and BDD also did. Indeed, we all agree on the same thing: Code must be tested.

In the past years, a big part of the community shifted towards Functional programming. As a side effect, the paradigm shift brought us a more straightforward way of defining and writing unit tests.

So the thing is …

What is Functional programming?

Functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data — wikipedia

Let's take a look at an example of code which will be the system under test:

const showResponseMessage = (response, source) => {
 let message = source.message;
 if(response.data.status) {
   message += response.data.status;
 }
 if(response.data.title) {
   message += " " + response.data.title;
 }
 return message;
}

Pretty simple, right? The function receives a response and a source, we compose the message based on data received on the response, and we return it. Let's test it!

describe('It should show the error message', ()=> {
 const response = {data: {status: 'fail', title: 'edit'}}
 const source = { message: 'The post action had '}
 it('Adds the extra info', ()=> {
   expect(showResponseMessage(response, status)).toEqual('The post action had fail edit')  
 })
})

Looks simple, right? Straight forward I'd say, let's improve it:

const showResponseMessage = (response, source) => {
 let messageResponse = getMessage(source);
 const {status, title} = response.data;
 messageResponse = addStatus(status, messageResponse);
 messageResponse = addTitle(status, messageResponse);
 return messageResponse;
}
const getMessage = source => source.message;
const addStatus = (status, message) => {
 return message + " " + status
}
const addTitle = (title, message) => {
 return message + " " + title
}

I know, the number of code lines increased, at a glance, it just seems like a more sophisticated way of achieving the same thing. But, we increased the number of tests too, enhancing the overall quality assurance.

describe('It should show the error message', ()=> {
 const source = { message: 'The post action had'}
 const response = {data: {status: 'fail', title: 'edit'}}
 const {status, title} = response.data;
 it('gets the message from source', ()=> {
   expect(getMessage(source)).toEqual('The post action had')  
 })
 it('Adds Title properly', ()=> {
   let message = getMessage(source);
   expect(addTitle(title, message)).toEqual('The post action had  edit')
 })
 it('Adds Status properly', ()=> {
   let message = getMessage(source);
   expect(addStatus(status, message)).toEqual('The post action had  fail')
 })
 it('Adds returns the right message', ()=> {
   expect(showResponseMessage(response, source)).toEqual('The post   action had fail edit')
 })
})

In the first example, if we change the structure of the response and title, the test will fail, but we won't know why the test failed. Did it fail because of a missing response message or a wrong title retrieved as part of the response?

In the second example, we are testing each functionality separately. By assigning each function it's own responsibility, we make the code more maintainable, efficient, and versatile. For more information, check the single responsibility principle.

Let's consider the following scenario, suppose that our business logic changes, and we want to prevent the spaces on title and status. In such a case, we will have to create a function that receives a text and returns the sanitized version. To test that function, we have to create a test that solely asses that requirement; this test will not be related to showResponseMessage, but to space trimming.

That example points out a single case. However, as the logic and size of the application grow, the more relevant this approach to testing will become. When we start working with async calls, with the ability of composition and Higher-Order functions, we can make our "features" readable and our functions real units.

Furthermore, all of our original values are immutable. In the first example, we modified the message variable, now we don't, we still have our original message — And why is that important? Mutation means change, change adds complexity, opens the door for bugs, and sometimes makes things unpredictable.

When our code is predictable, self-explanatory, and easier to track and read, it's much easier to write cleaner tests.

'Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write a new code. ...[Therefore,] making it easy to read makes it easier to write.' Robert C Martin.

So stay functional for simple testing and happier code reviews :)

12 read time

Read more

End to End (e2e) testing is a technique that helps ensure the quality of mobile applications in an environment as close to real life as possible, testing the continuous integration of all the pieces that integrate a software automatically. On a mobile app, this could be particularly useful given the diversity of real devices and platforms our software is running on top of.

Due to the cross-platform nature of React Native, e2e testing proves to be particularly messy to work on. As a result, we have to write all of our tests bearing this in mind, changing the way we access to certain properties or query elements no matter the tool we use for connecting to it. Still, automation testing tools like Appium and WebdriverIO allow us to work over a common and somewhat standard interface.

The following instructions assume we already have React applications built with expo, and use Jest for our unit-testing solution.

Disclaimer: The following instructions are based on a Windows machine running an android emulator. output/commands may vary slightly on different architectures.

Setting Up Appium

  • Install required dependencies

$ npm i -D webdriverio babel-plugin-jsx-remove-data-test-id concurently

WebdriverIO will work as our “client” for the appium server in the case of JS. There is more to come regarding how to use other clients such as python.

babel-plugin-jsx-remove-data-test-id will help us remove unwanted accessibilityLabels from our mobile app, since that’s the preferred way of targeting elements for both IOS and Android platforms

concurrently will help us automate the running of appium server and jest to do our e2e tests

  • Install Appium Doctor

$ npm install appium-doctor -g

This will help us identify if we have all of the needed dependencies to correctly run appium in an emulator.

  • Run Appium Doctor

Depending on the host OS we want to test in, we could run:

$ appium-doctor --android

or

$ appium-doctor --ios

For this particular case I’ll be running the android version. This will prompt some output on the console. If we have all the required dependencies installed we should see a message similar to the following

Code Shot of Appium Doctor Messaging

If not all necessary dependencies are met at this point, instead of checkmarks before any given item you’ll see a red X symbol. Check the end of the input for more information on how to fix the particular Issues you’re prompted.

We’re not going to fix the optional requirements that appium-doctor prompts for the time being, feel free to go over those once you have the testing solution working.

  • Run Appium

By this point, you should be able to run your appium server without any issues, in order to do so just type

$ appium

You should see something similar to

Coding Screen of Appium Doctor Messaging

If you do so, congrats! you have correctly set up appium.

Now, let's set up our tests.

Write tests once, run in any platform

One of the key features of React Native is its ability to write code once and run it in both iOS and Android, that is what we want our mobile tests to behave in the same way. There are some limitations for this, since the only way we can write a selector for both platforms is through the accessibilityLabel attribute in React Native.

This may become an issue if your mobile app depends on accessibility features. Make sure to use correct, semantic and descriptive accessibility labels at any place you intend to use them.

If a great accessibility is not on the scope of your current project (it should), you can use accessibilityLabel as a perfect target for querying your elements, just make sure you don’t accidentally worsen the experience of people using screen readers or any other assistive technology.

In order to do this, we’re going to configure our babel setup to remove the accessibility labels whenever we build for production:

/// babel.config.js
module.exports = function() {
return {
presets: ['babel-preset-expo'],
env: {
production: {
plugins: [
[
'babel-plugin-jsx-remove-data-test-id',
{ attributes: 'accessibilityLabel' },
],
],
},
},
};
};

Let’s write our first test script now:

I’ve created a called LoginTest.spec.js inside a new folder called e2e. Inside the file you can find the following:

// myapp/e2e/LoginTest.spec.js
import wdio from 'webdriverio';
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;
const opts = {
path: '/wd/hub/',
port: 4723,
capabilities: {
platformName: 'android',
deviceName: 'emulator-5554',
app: 'my-app-name.apk',
automationName: 'UiAutomator2',
},
};
describe('Expo test example', function() {
let client;
beforeAll(async function() {
client = await wdio.remote(opts);
await client.pause(3000);
const pack = await client.getCurrentPackage();
const activity = await client.getCurrentActivity();
await client.closeApp();
await client.startActivity(pack, activity); //Reload to force update
await client.pause(3000);
});
afterAll(async function() {
await client.deleteSession();
});
it('should allow us to input username', async function() {
// Arrange
const field = await client.$('~username');
const visible = await field.isDisplayed();
// Act
await field.addValue('testUsername');
// Assert
expect(visible).toBeTruthy();
expect(await field.getText()).toEqual('testUsername');
});
});

That may be a lot of new code to digest at once, so let’s go line by line:

import wdio from 'webdriverio';

First, we import the WebdriverIO client. This is the main package that will include the functionality we need to query elements from the react app and simulate events on the emulator.

jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000;

This will tell our test runner (in this case jest) to make the tests error after a certain number of ms have passed. Here we’re setting it explicitly in the test, but if you’re using jest you can modify the testTimeout property on your jest configuration. If you’re using any other test runner, I’d recommend going through their documentation, most of them have a similar property.

const opts = {
path: '/wd/hub/',
port: 4723,
capabilities: {
platformName: 'android',
deviceName: 'emulator-5554',
app: 'my-app-name.apk',
automationName: 'UiAutomator2',
},
};

These are the configurations for our driver to know what to look for when using the appium interface to query and save elements.

You can get the device name going on your emulator > help > about

In order to generate an app from expo, you have to run the command:

expo build:android

And wait in the queue for it to build.

In this case, I placed the downloaded apk in the root folder for my project, and renamed it my-app-name.apk.

Since we’re using WebdriverIO, the automationName will be UiAutomator2, as that’s how appium recognizes it.

Since lines 18-33 are mostly about setup, we won’t focus on that for now. The next part focuses on line 34 and forward.

Writing the actual test

The idea of this test is just to showcase a normal flow on a test, therefore we will be dealing with a fairly simple use case: Checking that we have a valid username input:

const field = await client.$('~username');
const visible = await field.isDisplayed();

The first line allows us to query an item by accesibilityLabel. As I have previously mentioned, for more information about specific selectors go to the WebdriverIO documentation.

The second line checks whether our previously selected item is visible on the current screen, more information here.

await field.addValue('testUsername');

This line simulates user typing into the selected field. In this case, we’re inserting the ‘testUsername’ text inside the previously selected username field:

expect(visible).toBeTruthy();
expect(await field.getText()).toEqual('testUsername');

Lastly, we use Jest to check that the field is indeed visible on our Login Screen, and that the text on the given username field is the same as the one we wrote in it.

Running the test

Since we’re using Jest as our test runner on our React Native app, I’ve set up a command on my package.json to run the appium server and to run Jest in watch mode at the same time. It looks like this:

Screenshot of Command to Run Appium Server

Here we’re using concurrently, a simple npm package that allows us to run several npm scripts at the same time. In this case we run the appium server and jest in watch mode, add their names and different colors to easily recognize them in the console, and pass the standard input to the jest command. This way we can narrow down our tests or do things like run coverage reports.

With this done, we simply have to run npm run test:e2e on our console, and expect something like this:

Lines of code in appium

to be run, and something like this:

Lines of code

to be the output. If so, congratulations, you’ve correctly set up your integration tests for your react native app.

Wrapping up

While we’re far away from calling it a day on our e2e react app testing solution, the main automation testing setup it’s done. Next steps include integrating it with a CI/CD pipeline and making it work on IOS platforms.

Further Reading
https://webdriver.io/
https://discuss.appium.io/
http://appium.io/

No blogs matched this category, try applying different filters.