mobile it



The Myth of Bigger Teams: Why Smaller Can Be Better Myth of Bigger Teams: Why Smaller Can Be Better<p>​​​​In an effort to counter inefficiency and increase productivity, organizations often turn to increasing team size. The logic seems sound: more people means more hands on deck to tackle tasks and solve problems. However, this approach can often lead to growing overhead and inefficiencies.</p><p>Research has shown that small teams can often be more effective than larger ones. A study published in Harvard Business Review found that while large teams do advance and develop science, small teams are critical for disrupting it. Another study published in Forbes found that there is an ideal team size at which the benefits of putting more heads together are maximized and the drawbacks minimized.</p><p>So why do smaller teams often outperform larger ones? One reason is that large teams are more likely to have coordination and communication issues. Getting everyone on board for an unconventional hypothesis or method, or changing direction to follow a new lead can prove challenging with a larger group.</p><p>In contrast, smaller teams can be more nimble and adaptable. With fewer people involved, decision-making can be faster and communication more streamlined. This allows small teams to quickly pivot when needed and respond rapidly to changing circumstances.</p><p>This phenomenon is not limited to software development or business settings. In fact, examples can be found across different fields including military operations where smaller units are often able to operate with greater efficiency than larger ones.</p><p>Thus bigger isn’t always better when it comes to team size. Sometimes a highly productive team of 8 senior people can achieve better results than a mixed group of 60. Organizations would do well to consider this when trying to counter inefficiency.</p><h2>Effects of team size on performance</h2><p>But how exactly does this play out in practice? Let’s take a closer look at some real-world examples.</p><p>As more people are brought in to accelerate progress, it’​s not unusual for software development projects to expand in size, a phenomenon known as ballooning. However, this approach can often backfire as communication becomes more difficult and coordination issues arise.</p><p>For example, imagine a project with 60 developers working on different parts of the codebase. With so many people involved, it becomes increasingly difficult for everyone to stay on the same page. Code conflicts become more common as developers unknowingly overwrite each other’s work. Meetings become longer as everyone tries to get up-to-speed on what everyone else is doing.</p><p>Now imagine the same project with just 8 highly skilled developers working together closely. Communication is easier because there are fewer people involved. Coordination issues are less likely because everyone has a clear understanding of what their colleagues are working on.</p><p>In the military, for example, special forces units like Navy SEALs or Army Rangers typically operate in small teams of around 8-10 members. These elite soldiers are highly trained and capable of operating independently from larger units.</p><p>In contrast, traditional infantry units may have hundreds or even thousands of soldiers operating together in large formations. While these units have their own strengths such as overwhelming firepower or logistical support capabilities they may lack the agility and adaptability of smaller special forces units.</p><h2>Automation as an integral part of an organization</h2><p>As companies grow and evolve, it’s important to consider the impact of organizational change on teams and processes. One key area to focus on is automation. By automating tasks and processes, companies can improve efficiency and reduce the need for manual labor. Let’s take a closer look at how automation can affect teams and collaboration.</p><p>Automation can have a significant impact on organizational change. By automating tasks and processes, teams can minimize manual effort and errors, and enhance feedback loops throughout the software development lifecycle. This can lead to smaller chunks of better-quality code releases in less time. Automation can also reduce the need for basic data-input and -processing skills which will be particularly affected by automation.</p><p>The adoption of automation technologies will transform the workplace. Deliberately automating aspects of testing, code styling, integrating, and deploying should aim to reduce the time and human labor needed to develop, deploy and verify the product increment. DevOps automation is applied across the entire lifecycle, including design, development, software deployment, and release, as well as monitoring.</p><p>The primary objective of DevOps automation is to streamline the DevOps lifecycle by reducing manual workload. This automation results in several key improvements: it lessens the need for large teams, drastically reduces human errors, increases team productivity, and creates a fast-moving DevOps lifecycle.</p><h2>Why avoiding larger teams may be beneficial</h2><p>Some common antipatterns may arise when trying to involve more people rather than keeping a small team. As organizations grow in size they may implement measures such as code freezes or external approvals for deployment in an attempt to manage complexity. While these measures may provide some benefits they can also hinder agile development by slowing down decision-making processes.</p><p>They might as well include authoritative behaviors where senior members impose their will on others or create an environment where team members form informal silos within the team based on common interests. This all leads to a lack of trust where team members don’t trust each other’s abilities; this in turn keeps them from delegating tasks effectively. The whole environment just becomes much harder to work in.</p><p>In actuality, the bulk value or result created by a smaller team might be even bigger (let alone cheaper) than the result yielded by a larger yet rigid group. Smaller teams have fewer coordination issues, this allows them to make quicker decisions and deliver faster results.</p><p>When undergoing an agile transformation, companies should consider carefully how they scale agile development across multiple teams in order to avoid unnecessarily large teams. One way companies can achieve this is by creating cross-functional teams which helps reduce the need for scaling agile by merging various departments together.</p><p>Sometimes, however, having large teams becomes a necessity when the product is large and complex. In spite of this, there are frequent cases of software development where teams that could have stayed small if transformation had been done right. In such cases product size is still manageable by a small team, but a large group is now working on it. In such situations companies should aim at creating cross-functional teams, this reduces the need for scaling agile by merging various departments together.</p><h2>Conclusion</h2><p>To wrap up, here are a few basic areas for consideration:</p><ul><li>Conduct a thorough analysis: Before scaling up, teams should conduct a thorough analysis of their current processes and workflows to identify areas that may benefit from additional resources. This can help teams avoid adding unnecessary team members and instead focus on areas where additional resources will have the greatest impact.</li><li>Consider alternative approaches: Teams should also consider alternative approaches to scaling such as implementing new technologies or processes that can help improve efficiency without necessarily adding more team members.</li><li>Automate everything possible: Teams should automate everything necessary to minimize manual effort and errors, enhance feedback loops throughout the software development lifecycle. An effective continuous integration/continuous delivery (CI/CD) pipeline integrates automation tools and workflows an organization needs to build, compile, test and release its applications. Remote development teams cannot rely on end-users to perform robust user acceptance testing. They will need to automate platform, API, functionality, performance, and security testing.</li><li>Develop a clear plan: Teams should develop a clear scale-up plan that should include timelines, milestones and metrics. This can help ensure that everyone is on the same page and working towards a common goal.</li><li>Involve all stakeholders: When considering scaling up, it#39;s essential for teams to involve all stakeholders in the decision-making process to ensure their inclusion. This includes not only team members but also customers, suppliers and other partners who may be impacted by the decision.</li></ul><p>The key takeaway here is that organizations should carefully consider team size when trying to counter inefficiency or improve productivity. While adding more people may seem like an obvious solution it may actually lead to growing overhead and inefficiencies. While there may be instances where expansion is inevitable, disregarding the potential benefits of remaining small can prove to be expensive.</p>​<br>#agile;#development;#productivity;#project-management;#team-collaboration
How Management Buy-In Affects Agile Transformation Management Buy-In Affects Agile Transformation<h2><br></h2><p>Agile transformation can be a powerful tool for businesses looking to improve efficiency, productivity, and flexibility. However, the success of an agile transformation is often tied to management buy-in. As I've written in my previous post, in many cases, the motivation for an agile transformation comes from believing that the current organizational structure is misaligned and that agile will be a cure-all solution. Management may also have unrealistic expectations of the transformation process.</p><p>In reality, management must play an active role in the transformation process, working collaboratively with teams to identify and solve problems. This requires a willingness to hear bad news, make difficult decisions, and address structural and systematic issues that may be inhibiting agility, such as overly complex organizational hierarchies, rigid technologies, and inflexible approval processes. Without this buy-in and active participation, agile transformations can become nothing more than a superficial change with little real impact on efficiency or productivity.</p><h2>Definition of management and leadership</h2><p>There are multiple definitions of what management actually is. Let me cite the two classical ones:</p><p>Harold Koontz: <q>Management is an art of getting things done through and with the people in formally organized groups. It is an art of creating an environment in which people can perform and individuals and can co-operate towards attainment of group goals</q>.</p><p>F.W. Taylor: <q>Management is an art of knowing what to do, when to do and see that it is done in the best and cheapest way</q>.</p><p>So basically, when it comes to transitioning to an agile approach, there are two key takeaways managers need to keep in mind: first, they're responsible for creating an environment where people can be productive, and second, they need to figure out what to do when others are uncertain.</p><p>In addition, it is worth mentioning that although there is an overlap between the skills and qualities of a manager and a leader, they are not the same. A manager oversees and directs a team or organization to achieve its goals and objectives, while a leader inspires and motivates people to work towards a shared vision or goal. Although it is ideal for a manager to also possess strong leadership skills, it is not always necessary for a manager to be a leader as they can still effectively manage a team without necessarily inspiring or motivating them. However, in many cases, having strong leadership skills can enhance a manager's ability to manage their team effectively.</p><p>How does this apply in the context of an agile transformation?</p><h2>Top-down approach to agile transition</h2><p>From what I've seen, a few key attributes are critical for a successful top-down approach to agile transition. Managers must be willing to hear "bad news" and make active decisions in the business's best interests. The <q>average employee</q> in the company needs to be encouraged by managers to identify obstacles and suggest both workarounds and proper solutions.</p><p>To ensure smooth and effective work, managers must make their visions and expectations clear to team members. Although structural changes may hinder progress, it's important to recognize that some changes take time. A shared vision can motivate team members to find workarounds in the interim, while also fostering the belief that higher-level management is actively working towards a long-term solution.</p><p>Having clear orientation, vision, and understanding of context on a higher level can greatly improve motivation, productivity, and the relevance of solutions during an agile transformation. It can lead to more efficient and effective solutions as they are developed with the bigger picture in mind. A sense of direction and a clear vision can be a powerful motivator for people to persevere through challenging times. Like seeing the horizon during turbulent waters, it provides a sense of stability and purpose that can help individuals stay focused and productive. It's the leader's responsibility to ensure such a vision exists and is understood by others.</p><h2>Don't take it personally</h2><p>Managers who resist hearing strategic-level criticisms can hinder the progress of agile transformation. It's important not to take it personally. The broader the problem, the more difficult it is to resolve. Attempting to fix it carries both risk and reward, which is why the agile transformation was initiated in the first place.</p><p>When managers view criticism or obstacles as a cover for employee incompetence or failures, it can create a lack of trust that hinders effective management. This can lead to a tendency to micromanage and excessively monitor employees, which can ultimately undermine all the transformation efforts. Eventually, a lack of trust can lead employees to keep their ideas to themselves to avoid potential conflicts or arguments with their managers. This can hinder creativity and innovation and create a toxic work environment where open communication and collaboration are discouraged.</p><p>It's crucial for managers to actively participate and collaborate with their teams, facilitating problem-solving and decision-making instead of expecting the teams to sort everything out themselves. Some obstacles are outside the control of individual teams and require higher-level interventions or support from the organization.</p><h2>Make decisions - that's what leaders are supposed to do</h2><p>Decision-making in a business context involves a shared responsibility between managers and lower-level colleagues. Effective managers take responsibility for their decisions, even in the face of uncertainty. They actively seek out the information they need to make informed decisions and recognize that some situations may not have enough information, yet still require a decision. In contrast, some managers may try to shift responsibility elsewhere rather than taking ownership and accepting accountability for their decisions in such situations out of fear of failure. It is essential for managers to understand that managing uncertainty is a critical part of decision-making and to accept this responsibility. Lower-level colleagues play a crucial role in facilitating decisions by providing valid, precise, complete, and most importantly honest information.</p><p>To handle critical decisions, organizations can foster a culture of experimentation and testing or establish a structured approach to collect and analyze data for making informed decisions. By exploring various scenarios of potential outcomes, measuring their impacts, and proactively engaging with such models, organizations can break free from this pattern.</p><p>Effective managers approach decision-making with a healthy dose of skepticism, validating and cross-checking data before making any commitments. This also applies to creating plans and commitments during the sales process. It's important to note that the criticism and ideas for improvement from individual teams may not just involve structural and technical aspects but also target plans. A common pitfall is when experts are not involved in the sales and planning process, resulting in unrealistic plans. In such cases, the team should not be held accountable for being unable to adhere to an unrealistic plan. Creating such a plan is a decision that involves risk, which managers are responsible for evaluating, managing, and accepting. Agile transition might painfully expose such naive plans.</p><p>Delegating competence and responsibility is an essential aspect of effective management. However, it's important to note that managers should also be willing to accept the consequences of delegation.</p><h2>Overcoming fear and lack of trust</h2><p>The fear of change can often hinder the agile transformation process, and many managers may be hesitant to make changes due to various fears that are common to any human being. These fears include fear of failure, fear of the unknown, fear of losing control, fear of job security, fear of being exposed as incompetent, fear of losing status or power, fear of conflict or opposition, and fear of the extensive changes required by the agile transformation process. However, effective managers and organizations are able to recognize and manage these fears, while still moving forward with the necessary changes to improve outcomes. It is important not to take these fears personally, but instead to approach them with a solution-focused mindset - because paralysis may be the other option.</p><p>Fear and lack of trust can be significant barriers to organizational success, particularly during a transformation toward an agile culture. Although these feelings are valid and may have justifiable reasons, they can ultimately hinder progress. For an organization to move forward and become more effective, it is essential to foster trust, delegate competencies and responsibilities, and empower employees to make decisions. Most individuals are naturally motivated by changes that save time and effort, and a culture of trust and collaboration can facilitate this motivation toward achieving organizational goals.</p><p>By fostering a culture of trust and collaboration, organizations can overcome fears and barriers to agile transformation and empower employees to take actions that save time and effort.</p>​<br>#agile;#project-management;#team-collaboration;#scrum
Truly embrace asynchronous work embrace asynchronous work<p>​​In 2020 we experienced the most significant office exodus that forced people to work at home. Many of them found enough strength to resist the temptation of PlayStation and figured out ways to reclaim their time, focus, and get a massive load of work done. Isolation has one great advantage as it provides an opportunity for <b>uninterrupted productivity</b>. No manager can barge into your home office to schedule an impromptu status meeting. The time you spend working is genuinely yours. </p><p>The forced isolation is now over and we can choose our workplace. Some have remained at home while others return to the office for various reasons, such as having kids at home or their spouse being a manager. Having part of the team work on-site and part working remotely comes with its own challenges, but more on this hybrid scenario later.</p><h2>The return to the office</h2><p>Forcing people back to the office may backfire. They have gotten used to controlling their schedules and are reluctant to go back to the old days. Remote work has become popular and opened borders, so looking for a new job, even abroad, is easier than ever. The same applies the other way around: you can hire talent everywhere, not just in your office's physical location.</p><p>One argument for returning to the office is that people have better working discipline there than at home. It's up to anyone to decide which place has more disruptions and choose accordingly. Looking at a typical modern office with table footballs, drum hero sets, and four dogs chasing each other in a gigantic shared open space where people without noise-canceling headphones are doomed is debatable, at the very least. But it all boils down to trust. Do you trust your employees to work productively without a manager behind their backs? If not, you should be more considerate about hiring decisions rather than where people choose to work.</p><p>Adapting and allowing office and remote worlds to coexist makes a lot of sense: let people work from where they feel the most productive, and they will reward you with doing exactly that. It's OK that it still might be the office for some. You can benefit from the advantages of remote practices with part of the crew on-site and part remote. Some refer to it as a hybrid approach, but that’s not entirely on point.</p><h2>Asynchronous practices</h2><p>Let's rip the band-aid off quickly. There's no hybrid approach! Only an environment where applied asynchronous practices enable cooperation between on-site and remote people. Nothing else in between makes sense, as it only leads to the neglect of one group or the other. The same conditions and rules must apply to everyone, regardless of location. Asynchronous practices not only help connect the two worlds but also significantly improve productivity for office work. Here are a few tips.</p><p><b>Create and maintain a calm environment</b> so people can focus and not be disturbed for as long as they wish, regardless of the physical location. At home, we often set rules for when we don't distract each other. Why can't we do something similar in the office, the place set up for work in the first place?</p><p>Set boundaries and don't tap on people's shoulders if you need something. Imagine the person next to you is working from a different country and you can't contact them physically. Approach them asynchronously. If they don't reply, chances are they are focusing on something and the last thing they'd want to do is pause everything and talk to you in person. Don't rip people away from their thoughts because of your fantasy of urgency. It might not be as pressing as you perceive it to be.</p><p>The same rules apply to online space: don't go around your messaging app and expect people to react instantly. Some managers abuse those tools as an utterly unnecessary control mechanism to check if people are working. The chat app is not where the work gets done. Feel free to turn it off if you need to focus on something more substantial. </p><p><b>​Knowledge must be shared</b>. It's far from enough that it's been said in a meeting room. Verbal knowledge sharing is a no-go; remote people will be clueless and office people will forget. You must define and learn to use a well-known single source of truth. If you fail to do so, you only create space for assumptions and friction.</p><p>Plenty of project management software is here to help but choose wisely. If you don't, you will end up with three different messaging apps and another three for documentation, design, and progress tracking. That makes the single source of truth, well, not that much single. It also further invites an opportunity for focus disruptions.</p><p> <b>Knowledge must be comprehensive</b>. It doesn't suffice that it's written. Not only do others have to understand what you meant, but also your future self. Try to put yourself in your reader's shoes and re-read your writing. Does it answer questions, or does it raise more than it's necessary? </p><p>Some people, often those responsible for technical analysis (or writing horoscopes), think adding an obfuscation layer to the natural language is a great idea, making them sound more professional. What ends up happening later is that some poor soul has to decipher the gibberish leading them to a quest to find the original scroll with the ancient knowledge. This is work, not a role-playing game. If you expect a human to read what you wrote, write like a human.</p><p> <b>Leave people alone to do their work and share well-written knowledge. </b></p><p>The practice imposes extra discipline on a team, but you won't want to return once you start seeing the benefits. I'd go to great lengths to argue that you should opt for those rules even if your whole team works on-site. Let's now address the two remaining elephants in the room.</p><h2>Meetings and managers</h2><p>Meetings and their human equivalent, managers, are the two most influential relics of the old age and arch-nemesis of uninterrupted productivity. There is still a place for both, but the sooner we forsake the established office routine, the smoother the transition to an asynchronous and productive world will be.</p><p>Programmers work by organizing the thoughts they later output in the source code form. They often do that independently of each other and commit work additions asynchronously, so remote practices feel closer to them and accepting them is more straightforward. Managers, on the other hand, might feel out of their element in this asynchronous world.</p><p>Managers do not directly create value. Their most significant addition is removing barriers for the workers that do. A good manager shields others from the irrelevant to allow them to spend as much time as possible doing what they do best. Let designers design and programmers program. There's no value in keeping people verbally hostage in a meeting, but there is great value in doing the opposite.</p><p>This requires a mind shift, but there's a silver lining once you realize you employ self-organized people who don't need micromanaging and can work without much oversight. This shift frees managers and allows them to focus on the topics where they might contribute to the process meaningfully. There is no room for ego and certainly not for the illusions of authority—forget the management manuals of the 1990s. </p><p>People don't go around wondering who, for instance, van Gogh's project manager was. On the contrary, some jokingly speculate the famous painter cut off his ear when he received a letter with yet another meeting invite. But little did he know that meetings might also make sense in an asynchronous work environment.</p><p>There's just a different approach to organizing them. Instead of summoning a group of 15 people into an hour meeting, it can go like this:</p><ol><li>Write an agenda and briefly summarize the reason for the meeting.</li><li>Then write questions asking for answers that can solve some specifics.</li><li>Send out these questions. </li><li>Wait for answers.</li><li>Don't have the meeting.</li><li>Repeat.</li></ol><p>Organizing your thoughts using the written word helps you understand the issue and alleviates the fear of the unknown. It creates newly found insight that you can easily share as a valuable contribution. Writing down a problem forces you to understand it comprehensively. This process can sometimes be done independently without wasting the time of others.</p><p>In some cases, however, a synchronous meeting can be more productive. A quick pair programming session or a chat with a designer is practical now and then. But limiting the number of participants to those concerned with the topic is as essential as avoiding full-team calls where three-quarters are just muted passive spectators doing their laundry in the next room.</p><p>Could it really have been just an email? It might not be in some cases, and that's fine too. But be honest about your intentions and don't take other people's time off their hands lightly. Think twice if conducting numerous meetings isn't just a way to give the impression of being occupied. Time spent in a meeting is the time not doing the actual work.</p><h2>Writing</h2><p>The backbone of remote work is writing. The ability to express your thoughts is essential regardless of your position. It's a craft that gets better and easier the more you do it, and opportunities to practice are plenty: toots, tweets, daily standups, project READMEs, and even chat messages.</p><p> <b>You can also write a blog post for your company!</b></p><p>Writing is also a transferable skill. You can change a team role, a company, or even an industry and still benefit from writing well. No one can take that away from you.</p> <br>#productivity;#team-collaboration
How flawed motivations can derail Agile transformations flawed motivations can derail Agile transformations<p>Agile transformation has become a buzzword in the business world. Companies are eager to jump on the bandwagon and adopt Agile methodologies. The belief is that Agile transformation will increase productivity, efficiency, and speed, simplifying everything and making it faster. While this can be the case when done right, if the sole motivation for Agile transformation is focused on these outcomes and the company has a delusional idea about how difficult it will be to achieve them, things will go south. It's always a lot bumpier than anticipated.</p><p>This post is part of a series about the most common Agile transformation pains, as I've witnessed them in the organizations around me. This series focuses on the top-down hindrances. </p><h2>Speed, efficiency, transparency</h2><p>What's incorrect about the motivation mentioned above? Don't efficiency, effectiveness, transparency, flexibility, and speed embody the characteristics that the Agile culture promises?</p><p>In my view, the reason it falls short is that it lacks a crucial and integral aspect of Agile methodology, which is the concept of <q>failing fast</q> and promptly identifying and showcasing obstacles and challenges impeding progress. A true willingness to find problems sooner and improve collaboration must also be an integral and true part of the motivation.</p><p>The misconception I mentioned is problematic because it creates unrealistic expectations for what agile can achieve. Agile is not a quick fix for organizational problems. It's rather a fundamental shift in the way a company operates. It is a way of working that requires collaboration and a willingness to adapt. Everyone, including the senior management, must be willing to collaborate with teams to improve the environment for Agile work. The whole motivation stems from the belief that problems are caused by the disorganization of teams and wrong organizational structures.</p><h2>Transformation project - its end is just the beginning</h2><p>Regrettably, Agile transformation is often viewed by management teams as a silver bullet solution to a company's organizational issues. They mistakenly perceive it as a short, one-time investment that will provide immediate and long-lasting benefits. This misconception can lead to an overly simplified approach to Agile transformation, which does not consider the ongoing effort required to sustain it. Agile transformation requires continuous effort and commitment from both management and the teams involved.</p><p>Many managers mistakenly believe that adopting Agile is as simple as calling it a transformation project, allocating a budget, giving the project a fancy name, hiring consultants, and conducting a bunch of trainings. They think that these actions alone will suffice to achieve the transformation and their job is done. People just pat themselves on the back for renaming project managers as scrum masters and officially closing the transformation project. And then they sit back while the teams <q>self-organize</q> and Scrum Masters magically remove all obstacles. But that's not how it works. </p><p>Organizations often face structural and systematic problems that impede their agility. Every company has some - just their depth varies. These issues can manifest in various ways, including overly complicated organizational and decision-making hierarchies, dependence on inflexible technologies, convoluted deployment procedures, and rigid approval processes, just to name a few typical ones. </p><p>For example, a company that releases software updates twice a year with numerous dependencies, code freezes, centralized testing, and lengthy development-testing-acceptance loops will likely encounter significant obstacles when adopting Agile methodologies. The legacy processes and technology stack may be quite incompatible with Agile workflows, making it a challenge to achieve the desired level of flexibility and speed.</p><p>These inherent problems won't magically vanish during an Agile transformation - they'll just become painfully obvious and urgent. The good news is that teams will finally feel comfortable talking about them and trying to tackle them head-on. Problems will be found everywhere.</p><h2>Beware of creating a Potemkin village</h2><p>The flipside is that if this is not expected to happen, the whole transformation won't work. One must be willing to hear the <q>bad news</q> and be ready to make proactive decisions.</p><p>After years of simply accepting the problems, teams will suddenly start shouting from the rooftops about these issues, and senior management needs to step up and work with them to make the workplace more agile-friendly. If they don't, teams will remain stuck in a rigid environment. Everyone will just call himself with a new title, such as product owner or Agile coach. This reorganization is likely to be seen as <q>another waste of money</q> and a failure, with many concluding that <q>Agile doesn't work</q>. A Potemkin village.</p><p>All levels of an organization need to be ready to face these challenges and work together to find solutions. A decision to adopt Agile is just the first step. Even the managers must be ready to roll up their sleeves and get involved in identifying and solving problems that arise during the transformation. It's a team effort, and everyone needs to play an active role. The more complex the business structure is, the longer the whole transformation will likely take. This is an ongoing process that is unlikely to ever come to a complete end. But the deciding factor is if there's actually a will to start and keep undergoing an uncomfortable change.</p><p>One surprising fact about Agile transformation is that it might lead to more bureaucracy if not implemented correctly. For example, suppose a company adopts Agile without addressing underlying issues such as convoluted decision-making processes or rigid approval procedures. In that case, it may inadvertently create more bureaucracy by adding more layers to the process. This is because Agile requires constant communication and collaboration, and if these processes are not streamlined, it can result in even more delays and inefficiencies.</p><h2>True motivation: A sense of security</h2><p>In my experience, failed attempts at agile transformation often stem from a common underlying issue: a lack of trust. This can manifest in various ways, such as a tendency to monitor and control teams closely. After one such transformation I've seen teams being required to share their sprint commitments, burn-down charts, and velocities, and then having to explain themselves when they don't meet those metrics. This happened at the senior management level.</p><p>Such reporting activity created a false sense of security by prioritizing the appearance of stunning charts and numbers on paper rather than the actual value of the work being done. The focus was on keeping commitments rather than questioning the sense of those commitments and the overall plans. Needless to say, what was missing was a critical examination of the actual business value of the effort invested and the value of the things developed. So it was quite obvious what the true initial motivation for Agile adoption had been.</p><h2>Do you really want to go Agile?</h2><p>In conclusion, Agile transformation can be a powerful tool for organizations looking to improve their productivity, efficiency, and speed. However, it is essential to approach it with realistic expectations and a willingness to address underlying structural and cultural issues. Agile transformation is not a quick fix or a one-time investment but requires continuous effort and commitment from all levels of the organization. Managers must be ready to roll up their sleeves and work with their teams to identify and solve problems that arise during the transformation. </p><p>Furthermore, it is crucial to approach the transformation focusing on business value and not just metrics and appearance. So, before embarking on the journey of Agile transformation, think twice and ensure you are willing to fully commit to the process. Going Agile is about being able to react more fluidly to changing business circumstances, isn't it? If there's little willingness to address the underlying issues that hinder progress, what's the point of identifying them in the first place? That by definition hinders the fluidity from happening.</p><p>If fundamentally changing an organization, including its core cultural, technical, and process aspects for the better, isn't the honest motivation, then maybe it will be more comfortable to maintain the status quo and save the embarrassment that an attempt to perform an Agile transition would inevitably bring.</p>#agile;#productivity;#project-management;#release-management;#scrum;#team-collaboration
Challenges of Agile Development with Fixed Contracts of Agile Development with Fixed Contracts<p>In today's fast-paced business world, clients are constantly seeking the best of both worlds: the flexibility and speed of agile development, as well as the perceived safety of fixed-time fixed-price contracts. This trend of blending agile delivery with fixed contracts is becoming more and more prevalent as clients aim to find a balance between agile freedom and contractual security.</p><p>One potential reason behind this trend is that clients may be hesitant to enter into a lease agreement with a development team and instead opt for a fixed-time contract. This uncertainty may stem out of the unknown, a belief that a fixed contract offers more security for the scope of work, doubts about the supplier's ability to deliver on the agreed scope, or the client's own internal processes that prevent them from entering into such agreements.</p><p>This post covers such a hybrid model from the supplier's perspective.</p><h2>Uncovering the pitfalls</h2><p>When implementing an agile approach with a fixed-time fixed-price contract, a common structure involves a product owner from the client company. This dynamic can bring its own unique challenges as the supplier company is bound by the scope and price outlined in the contract, with the product owner significantly impacting the return on investment. In this scenario, trust is of the utmost importance as the supplier must rely on the product owner to make well-informed decisions regarding the project's direction and priorities.</p><p>One of the main risks for the supplier associated with this approach is the potential to deviate from the contract scope. Suppliers may want to do so to accommodate the client's requests and be more agile. However, as the contract is legally binding, the client may take advantage of this deviation and exert pressure on the supplier team. This poses a significant threat to the project's financial success as the supplier team may have already allocated budget towards items requested and discovered during the course of the project, leaving the client in a position of power and potentially exploiting the supplier team to the detriment of the project's outcome.</p><p>Furthermore, the typical behavior of a product owner in this situation is to focus on completing one feature area (epic) before moving on to the next rather than maintaining constant prioritization. This can lead to the desire of perfecting everything before progressing, causing further delays to the project and potentially damaging the supplier's budget. On the other hand, suppliers may have to fit the project budget at all costs, resulting in a loss of quality. The combination of both phenomena can be deadly.</p><h2>Balancing Flexibility and Control</h2><p>Balancing the complexities of agile development within the constraints of a fixed-time, fixed-price contract can be a challenging task. From a supplier's perspective, effectively balancing the benefits of agile delivery with the security of a fixed contract requires a strategic mindset from the very beginning. One common trap is for the supplier to overestimate the control of the product owner over the project scope without involving the development team in the process. To avoid this, it is essential to engage in ongoing negotiations about how newly prioritized items will affect the original scope and what to deprioritize. </p><p>The main motivation of the business relationship described is to deal more effectively with unplanned and unexpected work. Maintaining transparency about unplanned scope items that have been delivered and what needs to be exchanged is crucial. By implementing these practices from the beginning, the mindset of "trading" one item for another can become ingrained in the team's nature and working style.</p><p>It's also vital that the client understands from the outset that while an agile approach brings added flexibility in making the product more relevant and potentially better, it does not equate to a wildcard for obtaining more for less. The responsibility for decision-making goes hand in hand with this approach and must be made clear by the supplier's team. Furthermore, involving the development team in the process is crucial to ensure that the project stays on track. The team should be responsible for providing rough estimates of newly discovered items, allowing the product owner to make more informed decisions about prioritization.</p><p>Ultimately, managing scope in fixed-time fixed-price contracts relies heavily on a mutual understanding between the client and supplier. Therefore, honesty and transparency are crucial for the success of this approach. The supplier must provide realistic and accurate estimates for newly discovered items and be transparent about any obstacles or issues that arise during the project. Tracking development velocity may also be beneficial. In return, the client must be honest about their expectations and priorities and be willing to make trade-offs to keep the project on track.</p><p>Building trust through honesty and transparency is key to the success of this approach. Furthermore, having a solid understanding of the client's business and goals can help the supplier team to better align the project's scope and priorities with the client's needs and anticipate any potential roadblocks or challenges that may arise during the project.</p><h2>Make the contract work in favor</h2><p>Navigating the choppy waters of agile development with fixed contracts may seem like a breeze at first, but in reality, it takes a steady hand and discipline to steer the ship toward success. Creating a successful contract for agile development with fixed-time fixed-price contracts requires a balance of flexibility and control. As a supplier, it's important to approach the contract with a defensive mindset, taking into account that clients may not always be upfront about their expectations or try to expand the scope. Here are some key points to keep in mind:</p><ul><li>Be cautious when crafting the scope and contract, being aware of scope items that are prone to inflation, and carefully formulating them in the contract. Clearly state that anything outside of the scope is considered a change request, and anything not explicitly mentioned is out of scope.</li><li>Use the difficulty of defining a comprehensive scope in an initial contract to your advantage by stating that nothing not explicitly mentioned in the contract is included, which can level the playing field and motivate the client to be fair when trading new items for the original scope.</li><li>Create flexible payment milestones that can accommodate changes in the scope and maintain cash flow. For instance, the milestones can be triggered once a scope worth X gets finished.</li><li>Describe the roles and responsibilities of key stakeholders from the client, such as the product owner, key users, and testers, to ensure smooth and efficient communication and decision-making throughout the project. This includes specifying that decisions and feedback must be provided quickly to avoid delays and blockages on the supplier's end.</li><li>Such definition should include the process for acceptance and sign-off of scope items throughout the duration of the contract, rather than waiting until the end of the project to ensure efficient progress and increase transparency.</li><li>Clearly define general acceptance criteria for scope items and require a continuous client testing and acceptance process throughout the project.</li><li>Keep in mind that the client company may try to enforce delivery of the entire defined scope while diminishing the value of the items developed extra, and make sure the contract reflects that.</li></ul><p>In conclusion, while combining agile development with fixed-time fixed-price contracts can be tricky, it can also offer benefits for both parties. The contract should be viewed as a framework, keeping the development team working within a certain timeframe. The supplier should be mindful in formulating the scope items, making it specific enough for the client to have an idea of the product but not so strict that it limits the supplier's flexibility. Furthermore, trust and open communication between the client and supplier are vital in ensuring the project's success. It's important to be prepared for the fact that the client may try to enforce the original scope and to write the contract with that in mind. It's important to remember that the contract should serve as a backup plan in case things don't go as planned. But from experience when a contract gets pulled out and evaluated along the project, it is a telltale sign that the project is already in severe trouble. Thus the primary focus should be on building mutual trust through transparency and honesty. This approach is the most effective for successful long-term project outcome for both parties.</p><p>Still, there is no doubt that using a traditional agile delivery contract by hiring a team of experts is usually more beneficial for all stakeholders than adopting a hybrid approach when the situation allows.</p> ​<br>#agile;#project-management;#release-management;#scrum;#team-collaboration
Architectural missteps in view, presentation, and navigation missteps in view, presentation, and navigation<p>​​Every system and architecture tackles the test of time. It's an unfair battle, almost impossible to win. That doesn't mean we should surrender and hack unsustainable components without the ambition of longevity. We must develop them to deal with this challenge gracefully and try to defer the inevitable as long as possible.</p><p>Nothing lasts forever, though, especially in a fast-moving industry like mobile app development, and some missteps are bound to bubble up along the way. Let's define the most common and explain possible ways to avoid them.</p><h2>Overly logical view</h2><p>Let's start with an obvious one, an arch-enemy to any solid architecture<span style="color:#000000;"><span style="font-size:11pt;font-family:roboto, sans-serif;color:#0e101a;vertical-align:baseline;white-space:pre-wrap;">—</span></span>a view that does way too much.</p><p>The view is an excellent, self-describing name for a software component. Its purpose is <i>to view</i> what's happening inside the system in a user-comprehensive, preferably friendly way. It renders to the screen, listens for content updates, and delegates events to someone else to handle.<br></p><p>When there's a need for an extensive user-interface redesign, it's the view's role to step up, take all the heat, and keep all the vital bits of the application unchanged. It's a straightforward process, as no important presentation or business logic gets in the way.</p><p>That's an example from an optimal world where the view is a thin layer that does just the minimal job it should. Yet some programmers complicate the layer with additional logic, like persistence, state management, or navigation. Those should have their foundation elsewhere, and it's no surprise that dealing with all this extra complexity might prolong redesign estimates from a few days to a couple of months.</p><p>As system and platform designers, Google or Apple aren't leading by example either. On the contrary, they encourage programmers to place too much weight on their views' shoulders by providing them with components that require such an approach. One example for all: the FetchRequest property wrapper, defined in SwiftUI, fetches entities straight from the Core Data store. To quote usage from docs: "<i>Use a FetchRequest property wrapper to declare a FetchedResults property that provides a collection of Core Data managed objects to a SwiftUI view.</i>" Ironic slow clap for encouraging programmers to couple views with data storage.</p><p>There are plenty of wolves in sheep's clothing, so keep your guard up and remember<span style="color:#000000;"><span style="font-size:11pt;font-family:roboto, sans-serif;color:#0e101a;vertical-align:baseline;white-space:pre-wrap;">—</span></span>just because you can doesn't mean you should. Your view should preferably not do much. The thinner the view layer is, the better. UI tends to change quite often, and keeping the view layer lean is a good practice for making swift and safe changes.</p><h2>Almighty view models</h2><p>As part of the presentation layer, view models are responsible for formatting content for the view and handling its events. It should be a comprehensive component, a little helper for the view, listening for changes, and handling presentation logic that lightens the load for the view.</p><p>Usage varies per project, but typically, it observes an application's state, transforms it into user-presentable data, and notifies the view. Unlike views, they are independent of UI frameworks, which makes them easily testable. That's not just icing on the cake but a massive step towards robustness.</p><p>However, they are often misunderstood and create a cesspool for what didn't fit elsewhere. So it happens that they handle business logic, navigation, and all other bits that don't have an official place elsewhere. Some scoundrels even compose requests and deal with networking! That's wrong on many levels; it defies the separation of concerns and tries to fit multiple components into one. This misplaced logic is not reusable and complicates further development on top of that. Such view models span hundreds of lines and compel us to recall massive view controllers from the Objective-C era.</p><p>Overly bloated view models are often present in architectures designed by proponents of MVVM who, in naive pursuit of simplicity, argue that three-layered architectures should easily cover all needs. Simplicity is, without a doubt, one of the goals, but the multi-hundred-line view model is anything but simple.</p><p><b>MVVM is not an architecture.</b> It's a pattern describing how to structure the application’s presentation layer. It would be unwise to build a complete application around any pattern. Why should MVVM be an exception?</p><p>Should you find yourself struggling with where to put something in codebases where the MVVM pattern serves as an architecture of the whole system, you might be on the right track. Navigation, networking, business logic, and many others don't have a well-defined place in incomplete architectures. You can lift the burden from view models with proper <a href="/Blog/Pages/application-domain-modeling.aspx">domain modeling</a>, define a spot for all those other concepts, name them, and be one step closer to a clear and comprehensive design.</p><h2>Lost in navigation</h2><p>In the early days of mobile application development, we didn't emphasize navigation much. Widely adopted architectural patterns such as MVC or MVP didn't have a letter in their name designated just for navigation, so we solely used system components such as UINavigationController, Activity, and Fragment, respectively, Storyboard segues. But these are massive system frameworks mainly “designed” for UI presentation. Their basic use complicates the view and further couples with the interface builder (used for scene designing) in the worst case.</p><p>Fortunately, things have gotten a lot better in the last few years, and with architectural enlightenment have come plenty of new designs. Some have even had their opinion or designated components on how to handle navigation. That's how coordinators, wireframes, flow controllers, and so on came to be. However, extracting the navigation into its place has revealed issues hidden in plain sight, such as sharing data between the screens. Some architectures do address this, but it is often neglected or misunderstood, so state propagation becomes another navigation responsibility.</p><p>The state dramatically complicates the situation for everyone involved in navigation. It must be obtained from the call site and passed to the next scene, which decides where to store such an incoming state. And it doesn't just end there. Once you wish to return to the previous scene, you need to take the state back with you and decide whether or not to replace the last one. That doesn't sound very easy, even for small-scale apps; imagine making sense of this in an app with hundreds of screens.</p><p>When you take a step back, however, you will notice that it is not so much a question of navigation. The problem is in state propagation and its coupling with navigation.​ <a href="/Blog/Pages/swift-ui-and-architecture-state.aspx">Decoupling state to its place​</a> significantly improves usability, testability, and simplifies navigation. It also makes it clear as to who owns the state and where the source of truth is.</p><h2>Architecture-agnostic</h2><p>The post might seem to focus more on a separation of concerns than architecture, but those two go hand in hand. Once you realize the bloated multipurpose components are too hard to tolerate, you start to look for something more cultivated than three-word patterns dressed as architectures. More layers do not equal more complexity. They bring order, and clarity, and leave no place for presumptions (which lead to unwelcome pull-request surprises and heated discussions).</p><p>The resulting product is not the only and most important value we produce. By making the software genuinely soft, we can deliver continuously, with the same effort, and in the long run. That's an essential feature valued in any field by any business.</p> ​<br>#architecture;#view;#presentation;#navigation
Application domain modeling domain modeling<p>Software projects are about telling computers what people want to do. Programmers are the ones who speak the computer language, but ordinary people aren't predestined to think and communicate the way a computer does. They are usually good at telling what they want to achieve and what is the purpose. Then it's the programmer's task to translate the purpose into computer language.</p><p>This arrangement leads to an unintended limitation. When a person needs to tell something to a computer, they need a programmer. When people need information about computer behavior, they need to ask a programmer. Programmers are a bottleneck in this process.</p><p>But what if we can design the project so the code is understandable even for ordinary people?</p><h2>Enter the domain</h2><p>A domain is a part of every project that does the important things. The business logic resides there together with industry rules and policies. The domain must be articulated unambiguously for everyone.</p><p>The domain shouldn't be too technical. There should not be transactions, exceptions, wrappers, or gateways. Ordinary people do not understand these terms but need to understand the domain. Although programmers understand these technicalities, they are ambiguous, and two programmers may imagine a different mechanism under these terms.</p><p>The domain should be full of real-world objects. We should see purchase orders, money amounts, other people, or actual goods. These objects can be virtual, like card transactions, but need to be recognizable to everyone.</p><p>Kotlin exhorts for readable code. This is one of its main characteristics. And we can use it to model our domain.</p><p>The real-world objects are usually modeled as <span class="pre-inline">data class</span> with read-only properties. Any modification needs to be done by a generated <span class="pre-inline">copy()</span> function that prevents unintended state updates or inconsistencies.</p><p>Some objects or data items like Social Security Numbers are so simple that one may tend to represent them as a primitive type like <span class="pre-inline">String</span> or <span class="pre-inline">Int</span>. This is good for program efficiency, but a person may unintentionally swap it with some other information of the same primitive type and introduce a severe error. To overcome this, we may introduce a <span class="pre-inline">data class</span> to wrap the information and give it a unique type. This will work, but its overhead may consume an unacceptable amount of resources when used at a larger scale. Kotlin <span class="pre-inline">value class</span> is a great fit for such use cases. It assigns a unique type to a simple data item while still keeping its memory footprint small.</p><h2>Domain actions</h2><p>Domain objects are important, but they are useless unless we can take action with them. A purchase order is to be placed or canceled. A parcel with a new pair of shoes is to be shipped or claimed. And we need to model these actions as well.</p><p>The first thing is the name. <span class="pre-inline">Action</span> in programming is quite an overused, and generic term and it does not work well for us. Some teams name them <span class="pre-inline">Interactor</span> others use the term <span class="pre-inline">UseCase</span>, or <span class="pre-inline">Actor</span>. We will use the term <span class="pre-inline">UseCase</span> for the rest of this post.</p><p>A use case is defined as a single function with explicit input and output. Use cases have no state and can be called multiple times. Let's try to define them in Kotlin. </p><p>It would be nice if a <span class="pre-inline">UseCase</span> may have a single input and single output so we can define a base type for all use cases with inputs and outputs defined as generics. But in the real world there are actions that may have more inputs, so this is not feasible, is it?</p><pre><code class="kotlin hljs">class FindDriverUseCase { fun execute(position: Coordinates, destination: Coordinates) } </code></pre><p>This approach will work technically, but it does not tell the whole story for people unfamiliar to the context.</p><p>Introducing a specific type for use case input will actually help to understand the context and works as an extension point for further feature evolution.</p><pre><code class="kotlin hljs">class FindDriverUseCase { fun execute(input: PotentialRide) } </code></pre><p>Great, after using this approach for a while, you'll realize that some use cases have their input and output optional. That's fine, Kotlin has built-in nullability in the type system, doesn't it?</p><pre><code class="kotlin hljs">class FindStoresUseCase { fun execute(input: Country?): List<Store>? } </code></pre><p>The use case finds all our company stores. We may want to get a list of all of them or to filter them by a given <span class="pre-inline">Country</span>.</p><p>The definition of input as <span class="pre-inline">null</span> on the use-site is not very understandable in this case. Also, it is hard to guess what <span class="pre-inline">null</span> as returned result actually means. A little bit more modeling will fix this:</p><pre><code class="kotlin hljs">sealed interface For { object AllCountries: For data class SingleCountry(val country: Country): For } sealed interface StoresResult { object NotAvailable: StoresResult object OutOfSync: StoresResult data class Available(val stores: List<Store>): StoresResult } class FindStoresUseCase { fun execute(input: For): StoresResult } </code></pre><p>It seems to be a good idea to deny the value <span class="pre-inline">null</span> as use case input or output at all. Let's introduce a base type and force the generics to be based on <span class="pre-inline">Any</span> that effectively forbids <span class="pre-inline">null</span>: </p><pre><code class="kotlin hljs">interface UseCase<in Input: Any, out Output: Any> { fun execute(input: Input): Output } </code></pre><h2>Actions namespace</h2><p>Quite often, we have a few use cases working with similar objects:</p><p><span class="pre-inline">SubmitPurchaseOrderUseCase</span>, <span class="pre-inline">CancelPurchaseOrderUseCase</span>, …</p><p>These class types may quickly pollute the project's namespace and make it hard to navigate.</p><p>We should try to group them somehow under a shared namespace. Kotlin doesn't have support for namespaces (<a href="">yet</a>). We can supersede it by grouping the use cases under a single <span class="pre-inline">sealed interface</span> for this purpose. You can use <span class="pre-inline">sealed class</span> or <span class="pre-inline">object</span> as an alternative, but the memory footprint would be slightly bigger.</p><pre><code class="kotlin hljs">sealed interface PurchaseOrderUseCase { class Submit { … } class Cancel { … } } </code></pre><h2>Kotlin call site</h2><p>Now let's look at the call site:</p><pre><code class="kotlin hljs">val purchaseOrder = PurchaseOrder(...) val submitPurchaseOrderUseCase = PurchaseOrderUseCase.Submit() val result = submitPurchaseOrderUseCase.execute(purchaseOrder) </code></pre><p>We can polish it with a little trick called Invoke operator. When a Kotlin function named <span class="pre-inline">invoke()</span> is marked as <span class="pre-inline">operator</span>, its invocation may be replaced by the use of <span class="pre-inline">()</span> operator.</p><p>When applied to our base type</p><pre><code class="kotlin hljs">interface UseCase<in Input: Any, out Output: Any> { operator fun invoke(input: Input): Output } </code></pre><p>the call site can be simplified to</p><pre><code class="kotlin hljs">val purchaseOrder = PurchaseOrder(...) val submitPurchaseOrder = PurchaseOrderUseCase.Submit() val result = submitPurchaseOrder(purchaseOrder) </code></pre><p>Notice the use case instance name change, where the <span class="pre-inline">UseCase</span> suffix has been omitted, and its invocation now looks like a standard function call. If it is used in an obvious context, we may shorten the use case instance variable name even more and call it simply <span class="pre-inline">submit(purchaseOrder)</span>.</p><h2>Swift call site</h2><p>Until now, we were only calling our use cases from Kotlin code. On Kotlin Multiplatform projects, it is common to share the domain logic between all targeted platforms. Let's check how a use case may be used in another language. We will take the example of a mobile application implemented both for Android in Kotlin and iOS in Swift.</p><p>First, let's try to call it the same way we do in Kotlin.</p><pre><code class="kotlin hljs">val submitPurchaseOrder = PurchaseOrderUseCase.Submit() val result: SubmitResult = submitPurchaseOrder(purchaseOrder) </code></pre><p>This code has two major problems. The invocation operator is unavailable, and the result is not of type <span class="pre-inline">SubmitResult</span>. Let's start with the latter one.</p><h3>Swift generics</h3><p>Generics in swift are available only for <span class="pre-inline">class</span>, <span class="pre-inline">struct</span> and <span class="pre-inline">enum</span>. A very similar thing for <span class="pre-inline">interface</span> is called associated types, but its characteristic is incompatible with Kotlin generics.</p><p>This is why Kotlin Multiplatform has Swift generics support only for classes. To fix this in our project we need to define our base type as an <span class="pre-inline">abstract class</span> instead of an <span class="pre-inline">interface</span>. This is actually not an issue as its implementations are classes anyway:</p><pre><code class="kotlin hljs">abstract class UseCase<in Input: Any, out Output: Any> { abstract operator fun invoke(input: Input): Output } </code></pre><h3>Swift function invocation</h3><p>Now let's fix the former problem with use case invocation. Swift language doesn't have an invoke operator like Kotlin. Instead, it has methods with special names, and one of them is <span class="pre-inline">callAsFunction()</span> that can be called with the use of <span class="pre-inline">()</span> symbol.</p><p>We may introduce this function to our use case base type but that may be confusing for use from Kotlin common code or Android code.</p><p>To make it available for iOS code only, we will provide different implementations of use case base type for Android and iOS using Kotlin's <span class="pre-inline">expect</span>/<span class="pre-inline">actual</span> feature. Its implementation just delegates the call to our standard <span class="pre-inline">invoke()</span> function.</p><pre><code class="kotlin hljs">// Kotlin Common expect abstract class UseCase<in Input : Any, out Output : Any> constructor() { abstract operator fun invoke(input: Input): Output } // Kotlin Android actual abstract class UseCase<in Input : Any, out Output : Any> { actual abstract operator fun invoke(input: Input): Output } // Kotlin iOS actual abstract class UseCase<in Input : Any, out Output : Any> { actual abstract operator fun invoke(input: Input): Output fun callAsFunction(input: Input): Output = invoke(input) } </code></pre><h2>Living documentation</h2><p>The domain is a part of every project that actually does the important things. When modeled properly, it suits so-called living documentation. It is understandable for any reader; anytime a logic is changed, the documentation also changes. </p><p>Anytime you find a piece of domain code that is not understandable, let's take a moment and polish it. Your future will be grateful to you.</p><p><br></p><p>Pavel Švéda<br></p><p>Twitter: <a href="">@xsveda</a><br><br></p>​<br>#domain;#architecture;#kotlin;#swift;#multiplatform
Unexpected bad practices bad practices<p>​​​​Some programming practices are so familiar to us that we use them automatically without much thought. Sometimes these techniques become obsolete; sometimes they are applied in the wrong context. Addressing such poorly experienced habits is often met with revolt. Especially by those who use them and perceive the topic as useful, so let's do exactly that!</p><h2>Marks</h2><p>Programming IDEs often recognize specific types of comments to help navigate across the codebase. Xcode’s <i>FIXME</i> lets other developers know that a piece of code deserves more attention. <i>TODO</i> is helpful when something is, well, to be done. <i>MARK</i> differs from the previous cases; it serves a documentation purpose. The same feature in IntelliJ IDEA/Android Studio is called r​egion.</p><p>Marks divide the source code into multiple parts using headings. That can make the code appear broken into logical units. If you are a reader familiar with the former Objective-C era of iOS development,​ know that this is just an updated <i>#pragma mark</i> directive.</p><p>Typical usage is in files with a large number of lines. <i>Marks</i> create the illusion of clarity by breaking them into pieces that supposedly belong together.</p><p> <b>The usage of marks in such cases is a bad practice.</b> Developers often abuse them to justify a file being too big. One should not depend on Xcode to make the code comprehensive and readable. Small and well-decomposed classes are more straightforward to reason about and navigate without IDE features. Especially for pull request reviewers using the web interface where those features are absent.</p><h2>Extensions</h2><p>Modern programming languages such as Kotlin or Swift allow you to extend classes, interfaces/protocols, structs, or enums to provide an additional implementation. You can divide your code into multiple pieces using extensions to outline what belongs closer together. Another usage is to make a convenience extension around another type you might not even own to make its use more intuitive. The possibilities are almost limitless. This isn't always a good thing, but first, a peek into history. </p><p>Extensions existed way back in Objective-C as well. If you're not blessed with experience with programming in such a language and had to guess the name for extensions, you'd likely be surprised. It's Categories! Another surprise is that Extensions are a thing in Objective-C too, but serve different purposes. What's interesting is the difference between both languages. Categories in Objective-C forced the developer to come up with the name. That's why files named in style <i>Class+CategoryName.swift</i> are often used even for Swift extensions. And more importantly, to use Categories, you had to import them explicitly.</p><p> <b>Extensions in Swift are an unnamed piece of code.</b> Such code may be more complicated for the reader to grasp. If multiple extensions of the same type exist, adding a name to the code and wrapping it in a type might help readability immensely.</p><p> <b>Improper extension of widely used types causes namespace pollution.</b> It's critical, before creating extensions, to ask whether all instances of the type should have such an ability. Should all UIViews have access to a blinking method? Does one specific subclass of UIView make more sense?</p><p>Some developers use extensions to break down the implementation of multiple protocols: which might also be a warning sign. If a class implements many protocols, it may be time to consider splitting it into smaller classes.</p><p>For trolls out there: you can make your co-workers mad by extending <i>UIView</i> with <i>translatesAutoresizingMasksIntoConstraints</i> and watch them compare it with <i>translatesAutoresizingMaskIntoConstraints.</i></p><p>But don't.</p><h2>Comments</h2><p>The ability to write comments might lead undisciplined programmers to create code of poor quality. Unfortunately, it's easier to neglect to name a variable and describe what's going on in my head with a complicated but not-so-clear comment. Easy should not be our goal. Brevity and clarity should.</p><p> <b>Great comment for poorly written code is still a code smell.</b> Don't just take my word for it. Robert Martin states: "A comment is a failure to express yourself in code. If you fail, then write a comment; but try not to fail."</p><p>Another reason is as the code lives in the repository and is modified and refactored, its behavior might change, and its name can express it everywhere it is called. But its comment is rarely updated and may become more confusing than helpful.</p><p>Documentation comments serve their purpose very well when you're designing an API for others to use. Remember that the API needs to stand by itself, and clarity is the priority. Don't use the documentation comments as an excuse for a lousy design.</p><h2>Structure</h2><p>The structure of a project is one of the first things you see when you check out a codebase, and it should outline the app's purpose at first sight. However, it is not an exception that some projects have folder structures inspired by the layers of architecture, e.g., View, ViewModel, Model.</p><p> <b>Project ​struc​ture based on architecture layers is a bad practice.</b> It makes reusability effectively impossible. Navigating through such a structure is unnecessarily complicated and becomes harder to maintain as the scope increases. It doesn't scale. Folders inspired by the architecture might have their place, not just at the top level. It should not be the first thing you see.</p><p><img src="/Blog/PublishingImages/Articles/unexpected-bad-practices-01-01.png" data-themekey="#" alt="" />     </p><p>See for yourself, what structure tells you more about the application?</p><h2>Dependencies</h2><p>Open source offers many libraries to simplify life, from UI components through networking to dependency injection solutions. It can often save a great deal of time and effort. On the other hand, this carries various dangers and limitations; using third-party libraries requires discipline, order, and balance.</p><p> <b>Randomly scattered third-party dependencies significantly reduce robustness.</b> Shielding the core of the application and using the libraries from the outer parts of the architecture helps mitigate the risk. Abstraction eases the process of replacing one library with another.</p><p>It's OK to utilize 3rd party dependencies, but with caution. Ask yourselves: How much time will it save me? How much effort will it take to replace? Can I install enough defense mechanisms to protect the application? </p><p>The silver bullet to protect your app, though sometimes tricky or impractical, is to have the import of the dependency in only one place.</p><p>We've had the pleasure of taking over multiple apps that were impossible to maintain anymore due to this problem. Without abstraction, no longer supported (or closed sourced) libraries disintegrated the codebase. External dependencies should never hold your product hostage.</p><h2>Tests</h2><p>Test-driven development is a programmer's good manners, a discipline overflowing with benefits. Technical impacts are a blog post by itself, if not a series. Non-technical impacts such as easy onboarding of new team members and executable documentation that cannot become obsolete speak for themselves.</p><p>Yet they are often neglected. A complete absence of tests is the apparent first and most common violation, followed by writing tests after the production code, which mitigates all the benefits and introduces other obstacles.</p><p> <b>You must write unit tests first - before production code.</b> Testing first will prevent you from creating code that's too complex. It will guide you through building components of the right size. The big classes are challenging to test, and the tests will direct you to decompose them into smaller ones.</p><p>Tests written after production code are inherently lower quality and can even be misleading. Unless you write the production code as proof of the first failing test, it is impossible to say whether the tests assert what they declare. It is then questionable how well such tests protect the system under test.</p><p>If you write tests after implementation, you may find a component challenging to test, which is impossible with a test-first approach. You can't create untestable code!</p><h2>The devil's in the detail</h2><p>Even the mundane can be harmful if we do something too automatically and with less attention. Challenge the ordinary and seek bad practices that you wouldn't expect.</p> <br>#xcode;#swift;#kotlin;#productivity;#team-collaboration
Development rules for better productivity rules for better productivity<p>​Each project has its own rules for development. Most often, these rules describe development practices and work with a version control system (VCS) that outlines how to test and deploy the product, the structure, the architecture of the project, and the code style, but the rules can also include the basics of secure development and more.</p><p>These rules can be unwritten but are usually defined and recorded in a shared space where everyone has access to them. Yet more important is how these rules are applied and enforced in practice.</p><h2>Wise men know it best</h2><p>Some people believe that pair programming or code review is an appropriate platform for rules revision. Participants can agree on the application of the rules or change them based on context. When developers approach this conscientiously, the result can be a project that may not be consistent, but its individual parts will be in the best possible shape.</p><p>This approach may lead to better results for a short period of time at the start of a project, but its shortcomings will start to become apparent over time. Even experienced developers and technical leads are just people. They can occasionally get tired or simply overlook something. Thus, minor deviations from the agreed-upon rules pile up and begin to form so-called technical debt.</p><h2>Time trial</h2><p>The next aspect that reflects in time is the expansion of the project, and this is on two levels.</p><p>The first is the expansion of the product itself. As the product becomes successful, it receives new and more sophisticated features that begin to connect previously simpler and independent features. This is where the small deviations and inconsistencies that at first seemed good for the functionality start to show up. The problem is that now more of these functions need to be compatible with each other, but they are not ready for it.</p><p>This is not just a problem of incompatibility of features. Often, well-intentioned developers try to reuse existing components as much as possible to avoid code duplication. They forget the rule that we can reuse a component when we expect the same behavior but also have the same reasons to change. If this condition is not met, the Single Responsibility Principle is violated and the project has low flexibility for future development.</p><p>The second level of project expansion is the development team itself. Once the product becomes successful, sooner or later it leads to the expansion of the development team. The new team members do not know the whole genesis of the project and thus do not have the same understanding of the rules as the older members who set the rules themselves. This leads to misunderstandings and yet another minor deviation from the agreed rules, which again increases the technical debt. A side effect is an increased need for communication during pair programming and code review, which reduces the overall productivity of the team.</p><p>These problems in project expansion are not limited to large development teams, but also happen to smaller ones. For example, when a two-person team introduces two new developers, the productivity of the team may hardly change. And all this is due to the circumstances described above. Without knowing the cause of the problem, it can lead to further blind "strengthening" of the team and make it even worse.</p><h2>Tripping comes before a fall</h2><p>When a development team repeatedly fails to finish agreed features or is unable to release a new version of a product for technical reasons, one of the critical scenarios occurs. At this point, people outside the standard development team get involved in discovering the cause and solving the problem. Together, they all work under stress and with a lot of human effort to get the development back under control. It is only at this point that a retrospective analysis takes place to uncover the true causes of the problems.</p><p>Yet the accompanying symptoms and spring of these problems have been manifesting themselves for a long time in advance. A few subtle situations as examples: </p><ul><li>A developer repeatedly receives feedback on misnaming during code review.</li><li>A ticket in the project issue tracker does not contain a reference to the implementation due to a typo in the project source code. </li><li>A feature that is still under development is enabled in the test version of the application.</li></ul><p></p><p>Often they just look like minor ambiguities, individual mistakes, or accidents that sometimes happen during development. When these situations recur, their negative impact on team productivity and the project's error rate quickly increases. But if we look closely at them, we can see blank spaces in the way we work that are actually easy to fill and solve the problem once and for all.</p><h2>Live rules</h2><p>To avoid the problems mentioned above, we need to have clearly specified development rules. Their content should reflect the individual needs of each project. For some projects, it will be critical to clearly define collaboration with the QA team and describe the release management of the product, while other teams will focus more on collaboration between developers within the development itself.</p><p>The more detailed and specific the rules are, the better their effect on the team's work will be. Therefore, it is not possible to start from a general template, but each team must define these rules themselves.</p><p>Sometimes we see cases where a team defines a few basic rules of a more general nature at the start of a project but does not develop them over time. Thus, the rules never accurately represent how the team works, and even the little they contain becomes meaningless over time.</p><p>Nothing is set in stone, and even an established team changes the tools it uses or discovers new ways of working over time. All these natural changes have an impact on the team rules. They remain alive and valid.</p><h2>Automate everything</h2><p>In the introduction, we briefly discussed the form the rules can take and the possible ways of applying them. To be most effective, rules must be applied automatically without the need for manual control. Likewise, we must think about the productivity of the team, which can be reduced by the influence of a large number of repressive rules. Therefore, tools that help team members automate certain steps are an integral part of this process. These tools save time and their output is naturally in line with the defined rules.</p><p>In practice, it is so common that Code Style or Project Architecture is enforced by automated rules, but at the same time, there are code templates and formatting tools that do most of the work for the developers without them being aware of it.</p><p>Most issue tracking tools provide a programmatic interface so that it is easy to automate the creation of a new development branch in VCS so that the new code is linked to a specific issue. Similarly, it is possible to create a VCS hook that checks that a corresponding issue exists for a given branch or commit for cases when the developer has created the new development branch manually.</p><p>Release management is a completely separate chapter. When releasing a new version of a product, there are generally routine and clearly defined steps that need to be performed. Here, automation not only gives us the assurance that the release of a new version will be done in an orderly and error-free manner but it also speeds up the process and allows for easy knowledge sharing between team members. A bonus is an easy automation of generating release notes, even if only for internal testers.</p><p>Testers will also appreciate the ability to configure the product for internal testing. They can toggle a feature flag, configure the environment the application runs against, or have the ability to simulate scenarios that are difficult to do manually. Besides the undeniable benefit of these test tools for testers, it has benefits for the developers themselves. They don't have to maintain more versions of the product than strictly necessary, which saves them time by fundamentally simplifying the build logic.</p><p>This is just a small sample of the rules we commonly encounter on projects. However, it is far from exhaustive of the options, whether they are related to quantity, depth, or sophistication.</p><h2>How far to go?</h2><p>Some rules may seem strict enough to restrict your freedom to work. Others may seem so vague that they will not have the desired effect. That's all right. Every team and every member has different needs and different perceptions of risk. All of this has a bearing on the form of the rules.</p><p>In our projects, we try to define the rules strictly by default. Over time, when we find that they limit us too much, it's easy to make the rule more generalized or turn it into a recommendation or warning. The opposite approach is considerably more complicated, because the team and its operation have already become accustomed to the more general rule, so it may not be possible to make a change overnight.</p><h2>Project sustainability</h2><p>When developing a product, in addition to the short-term goals of making the necessary features, we always consider the idea of long-term sustainability and viability of the project. Especially in mobile development, it is not an exception to the opinion that a project should be discarded once every 2-3 years and developed completely from scratch. This is a real disaster in terms of productivity.</p><p>In our portfolio, we have apps that are more than 7 years old and have gone through several major changes during their lifetime. On a business level, there has been a change in targeting a different sector of users and aligned with changes in branding and design. On a technical level I would mention the switch from Java programming language to Kotlin, or the transition of asynchronous work from a custom imperative solution to a reactive approach via RxJava and later Kotlin Coroutines. Even so, the development team is still only two people (while they are altering throughout) and at the same pace, it delivers new functionalities according to the business needs.</p><p>Clearly defined development rules and the consistency enforced by them have a major impact on the quality of the final product in every way.</p><p>Next time we will take a closer look at how some rules can be implemented and what tools we have for this.</p><p><br></p><p>Pavel Švéda<br></p><p>Twitter: <a href="">@xsveda</a><br><br></p>​<br>#productivity;#team-collaboration;#architecture;#automation