Jekyll2022-09-18T01:29:19+01:00https://vinileal.com/feed.xmlVini LealI am an iOS app developer with experience developing, testing, and deploying iPhone apps. In addition to publishing 2 apps to the App Store, I was awarded a WWDC 2019 scholarship.Vini Lealviniciusmoreiraleal+blog@gmail.comTech Debt2022-08-22T00:00:00+01:002022-08-22T00:00:00+01:00https://vinileal.com/agile/tech-debt<p>It is a well known fact that time is a driving force in multiple industries. For software development, it is a constant challenge, to be able to reconcile the fulfilment of stipulated deadlines with other needs of the project (or product).</p> <p>In this battle against time, often we are faced with the tough decision on making sacrifices in order to meet the deadlines. Sacrifices such as taking small shortcuts, implementing suboptimal solutions, and others.</p> <p>Although it is natural to think of quick solutions that are not always ideal, it bears to the developer (or team) to ponder and understand the boundaries between speed and quality. We need to take a pragmatic look at how we manage the quality of the project so that we don’t lose speed in the long run, after all, if we always take shortcuts, the code tends to become increasingly difficult to maintain over time, which, in consequence, slows down the team.</p> <p>In this article, I’ll discuss about the theory and application of the technical debt: a technique created so that software development teams can have this pragmatic strategy of managing the quality of the code.</p> <h2 id="what-is-technical-debt">What is technical debt</h2> <p>Tech debt is a software development concept that represents the implicit cost of an implementation or solution that is suitable for the present moment, not considering an approach that might take more time but could be more sustainable for the project.</p> <p>This concept can be compared to a financial debt (hence the name), which, by not being cleared, generates interest over time, making it harder to be paid.</p> <p>Besides that, on a software level, this debt generates difficulties to maintain the code and to add new functionalities, leading to delays and possible alterations on the final product.</p> <p>So in practical terms, let’s illustrate a scenario where a developer makes a decision to go with an approach that solves the problem, but it’s not <em>optimal</em>. Therefore, they are left with an obligation to repay it sometime in the future (coming back to that piece of code and fixing it). It’s a conscious decision made with the awareness of the need to come back to it.</p> <hr /> <h2 id="why-does-tech-debt-happen">Why does tech debt happen</h2> <p>There are different <em>types</em> of tech debt, and a wide range of reasons behind their occurrence.</p> <div class="notice--info"> 💡 Sometimes the expression <b>Tech Debt</b> is used to reference <i>lousy code</i>. For example: code badly written or with no test coverage. But it is much more than that. </div> <p>Classifying the different kinds of tech debt is helpful to address the identified problems, come up with solutions for them, and to communicate these thoughts. Also, having them well defined is very handy for communicating to non-technical people. According to Martin Fowler, these are the types of tech debt one can encounter when developing software:</p> <ul> <li> <p><strong>Inadvertent - Prudent:</strong></p> <p>A wrong choice regarding technology was made or there was a lack of iterative development methodology.</p> </li> <li> <p><strong>Inadvertent - Reckless:</strong></p> <p>There is a lack of technical knowledge to perform a given task or design a project.</p> </li> <li> <p><strong>Deliberate - Prudent:</strong></p> <p>There was not enough time to consider a proper approach to solve a problem, and the developers are aware of the need to deal with consequences.</p> </li> <li> <p><strong>Deliberate - Reckless:</strong></p> <p>There was a lack of time and a choice to ignore proper design choices was made.</p> </li> </ul> <hr /> <h2 id="how-to-eliminate-tech-debt">How to eliminate tech debt</h2> <p>Believe it or not, eliminating tech debt <em>completely</em> is just not possible. Tech debt is unavoidable, which means it will always exist, but it does not mean it cannot be managed. It is up to us to control it and make sure it doesn’t grow.</p> <p>It is so unavoidable that even if you can make the perfect decision on a project today, down the road, eventually the code will become suboptimal. There will be changes to the operating system, or the framework, for example. So your perfect decision may last for a while, but eventually there will be some work required to make sure these choices continue to work, or to add a new feature to this project.</p> <p>Eventually, the time to address the tech debt accumulated over time comes, and then, the developer either has to fix the old code before adding new code, or they have to fix it because a feature stops working due to system/framework/language changes.</p> <blockquote> <p>You <strong>owe</strong> the software you’ve written in the past a little bit of attention.</p> </blockquote> <p>Software development is, among many other things, making trade-offs between choices. Tech debt, will come in the future, and it is directly based on the choices made today. And these choices can be anything from frameworks you chose, to UI design choices, to architectural choices.</p> <p>Since there’s no ultimate way to eliminate it completely (as far as I know), let’s think about minimising it. There are a few tips to help:</p> <ul> <li>Don’t write spaghetti code</li> <li>Well defined architecture</li> <li>Take some time to evaluate/fix current code</li> <li>DRY, clean coding</li> <li>Have someone else look at your code (code reviews)</li> </ul> <hr /> <h3 id="identifying-tech-debt">Identifying tech debt</h3> <p>Tech debt presents itself in multiple shapes and sizes. It could be a poorly designed architecture, or just a method or class that does too much, for example. Due to its broad scope, sometimes, identifying tech debt might be a bit subjective, but by no means impossible.</p> <p>One important thing to have in mind is that shortcuts can lead to tech debt, so it is important to take note of why the decision to take this shortcut is being made and register somewhere that this needs to be addressed in a future moment.</p> <p>At other moments, tech debt might appear in response to a lack of technical knowledge on the developer side. In these scenarios, a more adequate decision could be made by asking the colleagues in the team what approach they would recommend.</p> <p>Apart from these mentioned ways, there are other cases where the code is already written. Then, identifying tech debt can be done by observing some traces. Those traces are often called <em>code smells</em>, and they symbolise how a piece of code could ‘smell bad’, because it is hard to understand or modify, for example.</p> <blockquote> <p>A code smell is a surface indication that usually corresponds to a deeper problem in the system. — Martin Fowler</p> </blockquote> <p>Here are some examples of tech debt in iOS Development:</p> <ul> <li>Massive View Controller</li> <li>Pyramid of doom</li> <li>Chain of calls</li> <li>Untested components</li> <li>Global mutable state</li> <li>Methods with many parameters</li> <li>Long methods or methods that do too much</li> </ul> <hr /> <h2 id="why-should-you-care-about-it">Why should you care about it</h2> <p>Even if we recognise tech debt as unavoidable and not inherently bad, it is hard for us to ignore the disadvantages it could bring to a product or a team, especially if neglected. This is because choosing the easier option, going for the quick fix leads to weaker software. And a weak software might not be able to support the business as it should, and, in a worse scenario, harm the business.</p> <p>In the words of Ward Cunningham, who popularised the metaphor:</p> <blockquote> <p>The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organisations can be brought to a stand-still under the debt load of an unconsolidated implementation, object-oriented or otherwise.</p> </blockquote> <p>A well known example of the impact of technical debt is the Y2K crisis. The decision to define years only by their last two digits (e.g., 1998 as “98”) was a remarkable space-saver in the early decades of computer processing when the price of digital storage was still astronomical. But when the world reached the new century, programs were still unable to distinguish between 1948 and 2048. Over $300 billion was spent worldwide to fix the problem before it was too late. By many estimates, that cost would have been significantly lower if the software had been updated over time. There was ample opportunity, as a man named Bob Bemer first called attention to the problem back in the ’50s.</p> <p>If not handled, tech debt can bring other undesired consequences to the business, apart from the financial consequences such as the example cited above. It could cause low team moral, because dealing with a messy code base can be really stressful and frustrating. Also, tech debt can accumulate in such a drastic way that it reaches a point where a rework is necessary in some parts of the code, or even a complete rewrite of the whole software.</p> <h2 id="wrapping-it-up">Wrapping it up</h2> <p>As we discussed, there’s no escape from it. From the very first line of code written, tech debt can appear. What will make a difference, however, is how it is managed. Accepting it is the first step, and recognising that eventually it will need to be settled, is equally important.</p> <p>For this, it is essential to discuss with the team and the management, quantify and prioritise it, and draw a plan to deal with it.</p> <p>From then on, we can be more demanding in terms of the quality of our code, set standards, write even more tests, and do our best to guarantee a high level of code quality.</p> <h2 id="references">References</h2> <p><a href="https://youtu.be/29pbPv0fLZA">Tech Debt: Low short-term risk with High long-term rewards - iOS Lead Essentials Podcast #008</a></p> <p><a href="https://www.firesideswift.com/episodes/2020/2/27/ep-119-thats-aggressive">Fireside Swift - That’s aggressive - Tech debt</a></p> <p><a href="https://martinfowler.com/bliki/TechnicalDebtQuadrant.html">Martin Fowler - Technical Debt Quadrant</a></p> <p><a href="https://martinfowler.com/bliki/CodeSmell.html">Martin Fowler - Code Smells</a></p> <p><a href="https://praxent.com/blog/brief-history-technical-debt">What is Technical Debt? A Definition and Brief History</a></p> <p><a href="http://c2.com/doc/oopsla92.html">The WyCash Portfolio Management System</a></p>Vini Lealviniciusmoreiraleal+blog@gmail.comSometimes the expression Tech Debt is used to reference lousy code. For example: code badly written or with no test coverage. But it is much more than that.Design Patterns in Swift - Decorator2020-11-08T00:00:00+00:002020-11-08T00:00:00+00:00https://vinileal.com/design%20patterns/design-patterns-swift-decorator<p>As I mentioned in the first article of this series, Design patterns are solutions to problems that someone once had and solved by applying a model that has been documented and that you can adapt entirely or according to the need for your solution.</p> <p>The original idea of Design Patterns came up with Christopher Alexander when he proposed the creation of pattern catalogs for architecture. Christopher himself defined the patterns in this way:</p> <blockquote> <p>“A pattern describes a problem that occurs numerous times in a given context, and it also describes the solution to that problem, so that this solution can be used systematically in different situations”.</p> </blockquote> <p>The main purpose of design patterns is to help developers to structure their applications in more flexible ways, easier to understand and maintain.</p> <p>In this article, I would like to share some thoughts about the Decorator, a Structural Pattern.</p> <p>Structural patterns focus on how classes and objects are composed to form larger structures, maintaining its flexibility and efficiency. The flexibility of object composition comes from the ability to change the composition at runtime.</p> <h2 id="decorator">Decorator</h2> <p>The decorator pattern (also known as Wrapper) is used to extend or alter the functionality of objects at runtime by wrapping them in an object of a <em>decorator</em> class. This provides a flexible alternative to using inheritance to modify behavior.</p> <h3 id="purpose">Purpose</h3> <p>Decorators offer a flexible way to add responsibility to individual objects. Unlike inheritance, decorated objects are not limited by their parent classes. Putting in other terms, a client has control over how and when to decorate the component.</p> <h3 id="applicability">Applicability</h3> <p>We can use the decorator to:</p> <ul> <li>Append responsibilities to individual objects dynamically and transparently, without affecting other objects.</li> <li>For traits or responsibilities that can be withdrawn.</li> <li>When subclassing is impractical.</li> </ul> <h3 id="consequences">Consequences</h3> <p>In general, this pattern is presented with a few particular elements. The first one would be an abstract representation of the component, that in swift can be a <code class="highlighter-rouge">protocol</code>. This is followed by a concrete implementation of this component, an abstract definition of a <em>decorator</em> for this component and one or more concrete implementations for this component’s <em>decorator</em>.</p> <p>A few of the characteristics of the Decorator Pattern are:</p> <ul> <li>The decorators have the same super-type or <em>conformance</em> as the object they decorate.</li> <li>More than one decorator can be used to comprise an object.</li> <li>Once the decorator has the same super-type or <em>conformance</em> as its decorated object (<em>decoratee),</em> it is possible to pass a decorated object in place of the original object.</li> <li>The decorator adds its own behavior before or after delegating the <em>decoratee</em> its work.</li> <li>The objects can be decorated at any moment, which makes it possible to decorate them dynamically at run-time, with as many decorators as needed.</li> </ul> <h2 id="practical-example-in-swift">Practical Example in Swift</h2> <p>There are many use cases for a decorator, but to keep things simple for this article, let’s make a salary calculator.</p> <p>In order to calculate the salary, we’ll input an hourly base rate, that the calculator needs to convert to a weekly value. With our weekly value, it will first discount the taxes and then discount the healthcare.</p> <h3 id="abstraction">Abstraction</h3> <p>So we begin with an abstraction <code class="highlighter-rouge">SalaryCalculator</code>, with the component’s definition.</p> <script src="https://gist.github.com/viniciusml/b8c7e9b65f7fd3c001804aa9ff3e93f2.js"></script> <p>Now we create a class that’s going to conform to the protocol, and implement the method.</p> <script src="https://gist.github.com/viniciusml/6bc1b88a4dc0e1099e51caab9a86c8ef.js"></script> <p>After that we can create our <code class="highlighter-rouge">TaxDiscountSalaryDecorator</code>, that, in our case, will apply the first discount we want.</p> <script src="https://gist.github.com/viniciusml/5667b3ece34014e769385d064f01be4a.js"></script> <p>As you can see, it takes as parameter an object (our <em>decoratee</em>) conforming to <code class="highlighter-rouge">SalaryCalculator</code> and also implements <code class="highlighter-rouge">SalaryCalculator</code>. This means that when the method is called, we can apply the discount, and forward the message.</p> <p>Next, the <code class="highlighter-rouge">HealthCareDiscountSalaryDecorator</code>. It follows the same principles as <code class="highlighter-rouge">TaxDiscountSalaryDecorator</code>, but this time, it applies a different discount.</p> <script src="https://gist.github.com/viniciusml/dc2b1cf5d1dabc524f84eff374a02e0d.js"></script> <p>Now we have all elements we need to accomplish our goal. So let’s see how our calculator works, with the discounts.</p> <h3 id="implementation">Implementation</h3> <p>In order to use our calculator with the discounts, we need to compose it with our decorators, like so:</p> <script src="https://gist.github.com/viniciusml/425bed89d8cc4aa348de8a0885a13fba.js"></script> <p>This way, we apply the discounts we need without modifying our original <code class="highlighter-rouge">ExampleSalaryCalculator</code> class. We’re extending it’s behavior without modifying it.</p> <h2 id="pros"><strong>Pros</strong></h2> <ul> <li>The use of a pattern provides the project with a universal style, which can make the code more comprehensible.</li> <li>The client’s code does not need to be modified in order to add new functionalities.</li> <li>The expansion of functionalities happen dynamically, which offers more flexibility to the codebase.</li> <li>It allows the components to be as simple as possible, delegating the addition of new functionalities to the decorators.</li> </ul> <h2 id="cons">Cons</h2> <ul> <li>Bigger number of classes utilized in the project, when compared to a version containing attributes and methods in a base class and implementation of specific functionalities in subclasses.</li> <li>It may become hard to read and understand the project, in case of overuse.</li> <li>It could decrease the project’s efficiency in case many decorators are used for an object with multiple public methods (that would require the decorator to offer the same public interface as the objects they decorate).</li> </ul> <h2 id="conclusion">Conclusion</h2> <p>As we could observe, the Decorator Pattern makes usage of conformance to be able to encompass the decorated objects. This way, when a decorator is composed with it’s component, a new functionality can be added, but not <em>inherited</em>.</p> <p>This small difference offers a huge amount of flexibly to create objects as needed without modifications to the existing components. As in all decisions, there are no silver bullets. The advantages of this pattern can be tremendous. So all in all, teams could take advantage of this pattern to solve a specific problem, observe the decision’s consequences, it’s impact in performance, and the evolution in the codebase as a whole.</p> <p>And, of course, there are some downsides to that, as we could notice. Therefore, it bears to the developers the evaluation of the project’s needs and the tradeoffs that decorators would bring.</p> <p>If you’re looking for more examples of how we can use decorators, I highly recommended these videos: <a href="https://youtu.be/y5SRUqDXYz4">Decoupling analytics from MVVM components</a> and <a href="https://youtu.be/jH7Zfi7TQt8">Testing code that uses DispatchQueue.main.async</a>. They explain some really good use cases, using Swift.</p> <h2 id="references">References</h2> <p>Design Patterns - Elements of Reusable Object-Oriented Software - Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.</p> <p><a href="https://gabrielschade.github.io/2018/08/13/gof-decorator.html">Design Patterns - Decorator</a></p> <p><a href="https://refactoring.guru/design-patterns/decorator">Refactoring Guru - Decorator</a></p>Vini Lealviniciusmoreiraleal+blog@gmail.comA decorator is used to extend or alter the functionality of objects at runtime by wrapping them in an object of a *decorator* class.Improving the Testability of Apple Pay With Dependency Injection2020-10-17T00:00:00+01:002020-10-17T00:00:00+01:00https://vinileal.com/tutorial/unit%20test/unit-test-apple-pay<p>We all know the importance of writing unit tests. But we also have seen many people who say that they take time to write, some things do not need to be tested, and all sorts of things that divide developer’s opinions as much as the endless debate ‘storyboards vs. programmatic views’.</p> <p>But leaving personal preferences aside, I believe people develop some resistance to determined things because they might not understand or take time to understand those things. And it happens with me regarding automated testing.</p> <p>The tests are useful to get fast confirmation that the code written works as expected and that when adding new features, nothing has been broken. Also, when working in a team, many different people might modify the project. So, once again, tests ensure the project’s integrity is maintained.</p> <p>In the matter of unit tests, I am always intrigued, by testing the implementation of my code that makes use of third party dependencies. That’s the case of integrating Apple Pay, for example. That’s what I would like to talk about today.</p> <p>The use cases for Apple Pay are pretty obvious. They very often involve the purchase of a product or service. And a wide range of apps are supporting it nowadays.</p> <hr /> <p>In order to make a payment using Apple Pay, there are some requirements. One of them is the creation of a <code class="highlighter-rouge">PKPaymentRequest</code> (part of <code class="highlighter-rouge">PassKit</code> framework), and the presentation of either a <code class="highlighter-rouge">PKPaymentAuthorizationController</code> or a <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code>.</p> <p>As <a href="https://developer.apple.com/documentation/passkit/pkpaymentauthorizationcontroller">Apple docs</a> state:</p> <blockquote> <p>The <code class="highlighter-rouge">PKPaymentAuthorizationController</code> class performs the same role as the <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code> class, but it does not depend on the <code class="highlighter-rouge">UIKit</code> framework. This means that the authorization controller can be used in places where a view controller cannot (for example, in <code class="highlighter-rouge">watchOS</code> apps or in <code class="highlighter-rouge">SiriKit</code> extensions).</p> </blockquote> <p>In this example I’ll use <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code>, since the project will only use it with <code class="highlighter-rouge">UIKit</code> for now. In the case of the example, the app will present the authorization view controller only if the user can make payments with one of the specified networks, provided by the method <code class="highlighter-rouge">class func canMakePayments(usingNetworks: [PKPaymentNetwork]) -&gt; Bool</code>.</p> <p>Following this idea, we can then create a <code class="highlighter-rouge">PaymentAuthorizationHandler</code> class, that creates the payment request, and completes with failure in case the networks are not supported. Like so:</p> <script src="https://gist.github.com/viniciusml/b424529a91d065448c87e03086bb66cd.js"></script> <p>When I try to unit test this behavior, I stumble upon the class function, which could be a barrier in the tests.</p> <h2 id="dependency-injection-to-the-rescue">Dependency injection to the rescue</h2> <p>One way overcome this limitation, is to use dependency injection to determine the possibility to make the payments that the specific test needs. I could either:</p> <ul> <li>Use constructor injection and set it in the initializer.</li> <li>Use property injection.</li> </ul> <p>When possible, I prefer to use constructor injection. So this is how this is how the <code class="highlighter-rouge">PaymentAuthorizationHandler</code> would be:</p> <script src="https://gist.github.com/viniciusml/d2e6a50291e37f7945214d85bc2eb64e.js"></script> <p>The typealias is nothing more than a closure representing the <code class="highlighter-rouge">class func canMakePayments(usingNetworks:)</code> signature. But with this change, it’s possible to pass, in production, the real method, and for test use, the value required for the test case can be provided by injecting it during the test setup. This also makes the test deterministic.</p> <p>A test is deterministic, or repeatable, if it produces the very same output when given the same input no matter how many times it is run.</p> <p>Now, in the test, the <strong>SUT</strong> (System Under Test) will have the value injected upon creation. This is how the test for the failure scenario looks like:</p> <script src="https://gist.github.com/viniciusml/b6c8f54a114893fb2c79fe8ac50748e0.js"></script> <p>Breaking it down:</p> <p>1 - The test needs to simulate a scenario where networks are not supported, so the <code class="highlighter-rouge">sut</code> is injected with a closure that returns <code class="highlighter-rouge">false</code>.</p> <p>2 - An optional error is declared, so it can be captured in the <code class="highlighter-rouge">requestAuthorization</code> method.</p> <p>3 - The <code class="highlighter-rouge">receivedError</code> is captured. In case an unexpected success message is received, the test simply fails with a message.</p> <p>The next scenario to be covered is the case when the networks are supported, but the <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code> fails to be initialized.</p> <p>The same approach will be used, but this time with the view controller initializer being injected via constructor injection. In case the initialization succeeds, the <code class="highlighter-rouge">requestAuthorization</code> completes with success. This is the finished <code class="highlighter-rouge">PaymentAuthorizationHandler</code>:</p> <script src="https://gist.github.com/viniciusml/7eac0ca781eba52ff251dfaaeda46030.js"></script> <p>Now, the following is happening:</p> <p>1 - The initializer signature is extracted into the typealias <code class="highlighter-rouge">ApplePayControllerFactory</code>.</p> <p>2 - An error case is declared to identify the cause of failure.</p> <p>3 - The initializer now accepts a new parameter, which is the <code class="highlighter-rouge">ApplePayControllerFactory</code>. In the case of production code, <code class="highlighter-rouge">PKPaymentAuthorizationViewController.init</code> is used as default value.</p> <p>4 - <code class="highlighter-rouge">requestAuthorization</code> completes with the new error case failure, when the controller fails to be initialized.</p> <p>5 - Finally the success case, the method completes with the initialized <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code>.</p> <p>And the tests follow the same style of the first one. Except that this time, to trigger an initialization failure, an empty (invalid) instance of <code class="highlighter-rouge">PKRequest</code> was injected, rather than a valid request, that was injected for the success case test.</p> <script src="https://gist.github.com/viniciusml/fbf11b2627156e7e0c407af628edfa66.js"></script> <p>So, let’s break it down.</p> <p>1 - An invalid request is passed to the authorization controller.</p> <p>2 - The request can be processed by the networks, by passing a closure that returns <code class="highlighter-rouge">true</code>.</p> <p>3 - There’s the assertion that when these conditions are presented, the failure output is <code class="highlighter-rouge">.unableToInitialize</code> error.</p> <p>4 - In the success scenario, a valid request is passed.</p> <p>5 - The request can be processed by the networks, by passing a closure that returns <code class="highlighter-rouge">true</code>.</p> <p>6 - The test asserts that the receivedController is not <code class="highlighter-rouge">nil</code>, as expected by the success case in the Result declared in <code class="highlighter-rouge">PaymentAuthorizationHandler</code>’s <code class="highlighter-rouge">ApplePayCompletionHandler</code> typealias.</p> <p>There it goes. This is a small example of how it is possible to manipulate the input for the tests, for implementing Apple Pay. Of course, there’s much more to it. There’s the display of <code class="highlighter-rouge">PKPaymentButton</code>,</p> <p>the received messages from <code class="highlighter-rouge">PKPaymentAuthorizationViewControllerDelegate</code>, the communication with a <a href="https://developer.apple.com/apple-pay/payment-platforms/">payment provider</a>, and other specifications, depending on the use case.</p> <p>And of course, there must be countless ways of achieving similar results, but this was the one I got to, and wanted to share. If you have seen something different, or thought of a different approach, you are welcome to share with me on <a href="https://twitter.com/Vini__leal">twitter</a>. 😄</p> <p>The full project, with a sample UIViewController, displaying the button and performing the <code class="highlighter-rouge">PKPaymentAuthorizationViewController</code> can be found on <a href="https://github.com/viniciusml/Articles-Vinileal.com">this repository</a>.</p> <h2 id="references">References</h2> <p><a href="https://developer.apple.com/apple-pay/payment-platforms/">Payment Service Provider - Apple</a></p> <p><a href="https://www.raywenderlich.com/2113-apple-pay-tutorial-getting-started">Apple Pay Tutorial - Getting Started - Ray Wenderlich</a></p> <p><a href="https://developer.apple.com/documentation/passkit/apple_pay/offering_apple_pay_in_your_app">Offering Apple Pay in Your App - Apple</a></p> <p><a href="https://martinfowler.com/articles/nonDeterminism.html">Eradicating Non-Determinism in Tests - Martin Fowler</a></p>Vini Lealviniciusmoreiraleal+blog@gmail.comIn this article, I'll share an introduction on how to perform unit tests on Apple Pay implementation.What is Open Sorce and How to Start Contributing2020-09-30T00:00:00+01:002020-09-30T00:00:00+01:00https://vinileal.com/open%20source/open-source-how-to-contribute<p>The world today is more democratic for those who want or need to use computers, more precisely those who need to make use of computer programs. But this was not always the case, and in part what made access to the computer world something a little simpler or less expensive was open source or open source software. But what exactly is it?</p> <p>An open source project is, in short, a project created and maintained by the people who use it.</p> <p>Let’s say you have an open source football field close to your home: one person will help you mow the lawn, another person will help paint the markings, another person will help you water, someone else will bring the ball and everyone can play! It is a collaborative software growth system.</p> <p>Contributing to open source can be a rewarding way to learn, teach and build experience on just about any skill you can imagine.</p> <p>In addition, you can interact with real professionals in the market and consult them to answer your questions, do code analysis and give tips for you to improve.</p> <h2 id="a-bit-of-history">A bit of history</h2> <p>We can understand a bit more about this concept and its associated benefits by telling the story of the most popular example of open source software.</p> <p>In the early 1990s, at the University of Helsinki, Finland, Linus Torvald created the Linux operating system from Unix, under the “<a href="https://pt.wikipedia.org/wiki/GNU_General_Public_License">GNU General Public License</a>”, that provides one of the many designations and parameters for software licenses, created by Richard Stallman of the <a href="https://www.fsf.org/pt-br">Free Software Foundation</a>].</p> <p>From this point, many people around the world downloaded Linux and started working with it. Among the many users, some were programmers, and because they had access to the source code, they analyzed it, learned about it and made modifications to improve it. For approximately three years Torvalds received all the changes and contributions and incorporated several of them into the original version, then released version 1.0 of Linux in 1994.</p> <p>The GPL, or GNU General Public License, is the type of license predominantly used in open source projects. Among the various aspects contained in the license, the terms state that if any modification to an open source program occurs, the distribution of the changed program must also distribute the source code that has been changed. That is, no one can use open source to produce proprietary code from it.</p> <p>But the most interesting aspect related to Open Source, is the collaborative performance that is normally associated and that we saw happen in the “birth” of Linux and that lasts until today.</p> <h2 id="advantages-of-open-source">Advantages of Open Source</h2> <p>Although some are controversial and questioned, particularly by those on the opposite pole, that is, those who produce proprietary code, there are some advantages and they end up being almost fundamentals of those who develop open source:</p> <p><strong>Transparency</strong> - to the extent that I have access to the programming behind each program executed, I have the possibility to know exactly everything it does, as well as the guarantee that nothing is happening that I would not allow or would like, for example, collection of personal data, which guarantee my secrecy and privacy.</p> <p><strong>Information</strong> - the technologies and the way things happen in terms of programming, are no longer exclusive to those who programmed and thus knowledge is shared.</p> <p><strong>Security</strong> - due to the fact that the code is public, anyone with the necessary knowledge can contribute to improve and even correct problems and flaws associated with security, which can only be done by the original programmers when they have proprietary code.</p> <p><strong>Maintenance</strong> - keeping the software up to date, as well as providing improvements, are not situations that depend only on the program provider, but possibilities available to many.</p> <p><strong>Cost</strong> - although free of charge is not guaranteed in 100% of cases, the number of programs in this condition is very close to that, which is a favorable point for computer democratization.</p> <h2 id="contributing-to-open-source-software">Contributing to Open Source Software</h2> <p>Contributing to open source projects is the gateway for you to code on large projects while working with some of the best developers in the world. There are infinite reasons to contribute, such as:</p> <h3 id="helping">Helping</h3> <p>This is can be a rewarding point. You can help developing new features for an application that you use, fix bugs for it and really experience those improvements on a day-to-day basis. Also, as you help other developers, you might get some insights of how to solve problems you’re facing or once you experience a similar problem in the future, you know where to look for information.</p> <h3 id="learning">Learning</h3> <p>If you love to develop, just like me, you will realize this is one of the most fantastic points of contributing to an open source project. Because you are seeing other people’s code and you will need to not only understand, but interact with it. Often the code can be quite old and you have to refactor or change something to get better with what you are doing. And by doing so, you can learn a great deal.</p> <h3 id="networking">Networking</h3> <p>An open source project community can be a wonderful way to meet devs with more experience and baggage than you. This is where you will have the opportunity to experience what it is like to work with the toughest guys on the market, and be able to gather different perspectives to solve common issues.</p> <h3 id="visibility">Visibility</h3> <p>When you start to contribute to the community you are more seen and consequently you stand out, but I would not advise to contribute thinking about this point, it is just a consequence.</p> <h3 id="portfolio">Portfolio</h3> <p>This is especially true for beginners who, in addition to not having much experience, do not have many projects to show. Nothing better than contributing so that you can have real projects in your portfolio and combine the experience of having worked with great names in the field.</p> <hr /> <p>There many reasons to contribute, but now the question remains: how to contribute? To make it easier I gathered some steps to start contributing.</p> <h2 id="find-a-project">Find a project</h2> <p>Certainly you already bumped into many open source projects, these are the cases of programming languages such as PHP, Javascript, Python, Ruby and frameworks such as AngularJS, React, Django, Rails that you have probably used or heard of, besides these there is a wide range of tools and libraries.</p> <p>There are basically two ways to learn about projects. The first way is to use it. With that, you be motivated to contribute, to help improve the project you have been using. This seems one of the most interesting ways, because by using the project you will get a clear visualization of features and bugs.</p> <p>The second way is for you to search for projects on the web to contribute. By not having prior knowledge of the use of the project, this can avoid some biases acquired when using it. If you choose this way I, there are some tools you can use to find these projects, such as:</p> <ul> <li><a href="https://www.codetriage.com">CodeTriage</a> - here will find open source projects, you will be able to filter by languages and select projects to receive issue newsletters.</li> <li><a href="http://yourfirstpr.github.io">YourFirstPR</a> - where you can start contributing to Open Source by finding great starter issues on GitHub and elsewhere.</li> <li><a href="https://github.com/mungell/awesome-for-beginners">Awesome First PR Opportunities</a> - A curated list of awesome beginner-friendly projects.</li> <li><a href="https://up-for-grabs.net/#/">Up For Grabs</a> - A list of projects which have curated tasks specifically for new contributors. These are a great way to get started with a project, or to help share the load of working on open source projects.</li> <li><a href="http://issuehub.io">IssueHub</a> - Allows you to search for open issues on projects by selecting specific tags.</li> <li><a href="https://hacktoberfest.digitalocean.com">Hacktoberfest</a> - an open event, happening on October, that encourages the growth of open source and contributions to the community. All backgrounds and skill levels are encouraged to join the challenge.</li> </ul> <h2 id="see-the-projects-guidelines-for-contributors">See the project’s guidelines for contributors</h2> <p>Most open source projects are on GitHub and when you access the repository, in addition to the project’s source code you will find the project’s README, which usually provides information on how to contribute in the contributing section. Each project has its own particularities and it is common to everyone to need to fork the project to start working on the code.</p> <p>Other projects contain a CONTRIBUTING file where relevant information on how to contribute to the project and how to keep it concise. In these cases, the README targets consumers of the project.</p> <p>The contributing file can also contain guidelines on how to open and claim issues. Also, how to announce a PR is ready for review.</p> <p>Many projects also provide a channel for communication. So if that’s the case, it is helpful to join it and discuss ideas, or simply to ask questions about a broad topic that does not fit directly on the repo’s issue.</p> <h2 id="check-the-projects-needs">Check the project’s needs</h2> <p>At this point, you found a project that you want to contribute to, and checked the rules to do so. But what needs to be done on the project, or what can be improved? The place where these information is usually present is issues section, which lists features and bugs that other users or the maintainers have detected and are asking for help. In some projects, there are labels identifying issues for those who want to start contributing. After choosing an issue, all you need to do is get your hands dirty.</p> <h2 id="write-some-code-and-open-a-pr">Write some code and open a PR</h2> <p>Aka. the best part!! At this point, you can perform the task you chose, check if the style of the code you wrote matches the project stile and guidelines, and make sure everything is working fine (at least for the parts you worked on).</p> <p>When finished, you need to open a PR from your fork / branch to the main repository of the project, to the branch defined in the rules. After opening the PR there may be interactions between the project’s contributors and you to adjust some things. After being approved, it is completed and will probably be available in the next release of the project.</p> <hr /> <p>Participating in Open Source projects is one of the best ways to evolve as a professional, create relationships with the community and prove your skills in any job applications. If you are looking to learn more about open source software, I recommend that you check the <a href="https://opensource.guide/en">Open Source Guides</a> website.</p> <p>And as a fun curiosity, in the <a href="[https://firstpr.me](https://firstpr.me/)">First PR</a> website you can check the first pull request made by any GitHub user. How cool is that?</p>Vini Lealviniciusmoreiraleal+blog@gmail.comA brief explanation of what is open souce software, its history and what are the first steps to start contributing.Common Git Workflows2020-06-12T00:00:00+01:002020-06-12T00:00:00+01:00https://vinileal.com/git/common-git-workflows<p>This article aims to expose a few of the approaches on how to work using workflows with git.</p> <p>If you already work with git as the main version control tool, you may have seen several approaches on how to use and control branches in a production or personal setting.</p> <p>And if you’re new to git, getting to know a bit about flows will help you become more familiar with how companies and open source projects often structure their workflows.</p> <p>Git-flow is a model, a strategy that helps groups in versioning a project. Workflows make the maintenance of corrections and introduction of new features more organized and secure.</p> <p>It is nothing more than a strategy created to improve the coordination of branches in a repository. This provides more fluidity to the process of adding new features and new releases.</p> <p>The strategy is relatively recent. It was released to the world in 2010 by Vincent Driessen. Git is a code versioning model, where branches can be compared to other branches. That is, it is possible to see the model as something like a tree and its (literal) branches. If you have already used this versioning system, you have probably noticed that, in general, there is an origin branch, which will be referred as the <code class="highlighter-rouge">main</code> branch in this article, and it is the one that usually bridges the repository with the production server.</p> <p>It is very common to see people using only one branch to commit to personal projects. This is not wrong, since it is very easy to control everything in a branch when developing alone, but the scenario changes a lot when we have to interact with more contributors, whether in an open source or private project.</p> <p>As a way to prevent complications with the main branch, Git-flow brought a more robust solution, mainly for projects that grow in size and which are constantly changing, and also because of the number of people interacting with the repository.</p> <p>In a project, for example, involving approximately 30 programmers, what would the project look like if everyone made their commits to the <code class="highlighter-rouge">main</code>? This might even be a valid strategy, but in conjunction with other strategies so that the team does not fall into the trap of putting something into production that is not fully tested.</p> <p>At these times, it is extremely important to have total control of what is being produced by your team, since that, at the same time bugs are corrected, new features are being implemented and this whole process should not prevent production code to be fully delivered to the customer or the stakeholders.</p> <p>In a more generic approach, it is common to use the <code class="highlighter-rouge">main</code> as the main branch of the repository, and whenever it is necessary to create a new feature or correct something, a new branch is created for each case. After the task is completed, the branch is merged with the corrections / new features, with the <code class="highlighter-rouge">main</code> branch.</p> <div class="notice--info"> <p>The branch would, in this case, be a pointer to the specific commit.</p> </div> <h2 id="git-flow">Git-flow</h2> <p>In Git-flow, something similar happens, but with a slightly more complex structure, which can help a lot in the organization and productivity of a team.</p> <p>We can separate Git-flow into 2 types of branches:</p> <ul> <li>The main branches, which are the <code class="highlighter-rouge">main</code>, and <code class="highlighter-rouge">develop</code>.</li> <li>Support branches, which are the <code class="highlighter-rouge">feature</code>, <code class="highlighter-rouge">release</code> and <code class="highlighter-rouge">hotfix</code>.</li> </ul> <p>For each branch there are some rules and recommendations to be followed.</p> <ul> <li>The <code class="highlighter-rouge">main</code> branch continues to bridge the release commits to production.</li> <li>The <code class="highlighter-rouge">develop</code> branch contains all the stable features that will later be merged into a <code class="highlighter-rouge">release</code> branch.</li> <li>It is only from the <code class="highlighter-rouge">develop</code> branches that feature branches are created. For each feature, a new branch is created.</li> </ul> <div class="notice--info"> <p>The nomenclature for new branches has been standardized over time. For new features, for example, you may want to name: 'feature/feature-name'.</p> </div> <ul> <li>The <code class="highlighter-rouge">feature</code> branch will always be created from <code class="highlighter-rouge">develop</code>, and returned via merge to this one. Once incorporated, it can be removed.</li> <li>After incorporating the new feature, it must be prepared to go into production. For this, another support branch is used, the <code class="highlighter-rouge">release</code>. It serves as a support to create a point where it should reflect what is expected from a next project release. In other words, it may occur that only after creating a set of new features, the team has a release ready. Once all the necessary features are ready in <code class="highlighter-rouge">develop</code> it will be possible to merge them into a <code class="highlighter-rouge">release</code> branch.</li> <li>With the <code class="highlighter-rouge">release</code> ready to go to the <code class="highlighter-rouge">main</code>, it is time to create a tag, that is an indication where it will contain a new version of the project. This is done in the <code class="highlighter-rouge">main</code> branch, right after the merge.</li> <li>Each merge done in the <code class="highlighter-rouge">main</code> must be done in the <code class="highlighter-rouge">develop</code> as well, to reflect the new tagged release. So, the branch Release can be removed.</li> </ul> <p><img src="/assets/images/git-flow.png" alt="" class="full" /></p> <p>This is a standard Git-flow. However, all projects are subject to unexpected production problems, or bugs. It is in this case that another support branch, the <code class="highlighter-rouge">hotfix</code>, appears. These have a very similar operation to the Release, with the difference that in this case, it is used for a more critical action. For this reason, when the hotfix is finished, the branch will be merged directly into the <code class="highlighter-rouge">main</code> branch. It also receives a tag in the <code class="highlighter-rouge">main</code>, after the merge, and the same must be done in the <code class="highlighter-rouge">develop</code> branch.</p> <p>This way it is possible to keep developers working on their features, while hotfixes are created. Then the branch containing the hotfix can be removed.</p> <p><img src="/assets/images/hotfix.png" alt="" class="full" /></p> <p>This is a summary of how Git-flow works. The approach may seem a little far-fetched at first. But with a little practice, the team adjusts to it and the benefits appear.</p> <h2 id="other-approaches">Other Approaches</h2> <p>There are many other branch management approaches, which can fit perfectly into what you and your team need. Proposed by Github in 2011, for example, Github Flow has the advantage of easy understanding and simplicity in use. The motivation behind this approach is the speed in the deployment phase. As the original Git-flow is focused on releases, there are a series of steps to be followed until deployment. In the case of Github Flow, the application is integrated several times a day, in the form of small implementations.</p> <p>A few characteristics of the Github Flow:</p> <ul> <li>Anything in the <code class="highlighter-rouge">main</code> branch is deployable</li> <li>To work on something new, create a descriptively named branch off of <code class="highlighter-rouge">main</code> (such as: <code class="highlighter-rouge">new-feature</code>)</li> <li>Commit to that branch locally and regularly push your work to the same named branch on the server</li> <li>When you need feedback or help, or you think the branch is ready for merging, open a pull request</li> <li>After someone else has reviewed and approved the feature, you can merge it into main branch</li> <li>Once it is merged and pushed to <code class="highlighter-rouge">main</code>, you can and <em>should</em> deploy immediately</li> </ul> <p>Another strategy, released in 2014, is Gitlab Flow. Also a simplified version of the Git-flow proposed by Vincent, in the Gitlab Flow:</p> <ul> <li>All features and fixes first go to <code class="highlighter-rouge">main</code></li> <li>It allows for <code class="highlighter-rouge">production</code> or <code class="highlighter-rouge">stable</code> branches</li> <li>Bug fixes/hot fix patches are cherry-picked from main branch</li> </ul> <p>In short, we learned how to control our branches by separating their responsibilities, without impacting on the <code class="highlighter-rouge">main</code>, which is where our stable code remains, and are identified with tags to version our releases and have a much more flexible control.</p> <p>If you are interested in learning more about how to use Git-flow, I recommend reading Vincent’s original <a href="https://nvie.com/posts/a-successful-git-branching-model/">article</a>. There is also an <a href="https://github.com/nvie/gitflow">extension</a>) created by git itself, to facilitate the process and thus simplify some steps.</p>Vini Lealviniciusmoreiraleal+blog@gmail.comA few of the approaches on how to work using workflows with git.Design Patterns in Swift - Template Method2020-05-23T00:00:00+01:002020-05-23T00:00:00+01:00https://vinileal.com/design%20patterns/design-patterns-swift-template-method<p>When we think about the software development routine, we can quickly identify that many times, the solution to a specific problem has identical characteristics, if not equal to that found in a previously developed project but the solution and the problem had not been documented. So, you are facing a similar problem, that was solved in the past, but there’s no record of <em>how</em> it was solved, making it extremely hard to reuse ideas and solutions. In this way, the occurrence of identical problems that are repeated in other contexts, consume more time and resources then they should, since the solutions were already explored before.</p> <p>In this way, Design Pattern are great allies. A Design Pattern can be described as the recurring solution to a problem in a context, even if in different projects and areas. The key terms here are: <strong>context</strong>, <strong>problem</strong> and <strong>solution</strong>. One context concerns the environment, and the circumstances within which element exists. The problem is the undefined issue, something that needs to be investigated and resolved. It is usually tied to the context in which it occurs. Finally, the solution refers to the answer to the problem that helps to solve it.</p> <blockquote> <p>The design patterns are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context. ― Gamma Erich, Helm Richard, Johnson Ralph, Vlissides John. Design Patterns: Elements of Reusable Object-Oriented Software</p> </blockquote> <p>In this article, I would like to discuss about the Template Method, a Behavioral Pattern.</p> <div class="notice--info"> <p>Behavior patterns focus on algorithms and assignment of responsibilities between objects. They describe not only patterns of objects or classes, but also patterns of communication between objects.</p> </div> <h2 id="template-method">Template Method</h2> <p>A template method defines the steps of an algorithm and allows the redefinition of one or more of these steps by subclasses. In this way, the template method protects the algorithm, the order of execution and provides abstract methods that can be implemented by concrete types.</p> <h3 id="purpose">Purpose</h3> <ul> <li>Define an algorithm framework in the form of a method, allowing some steps to be implemented by specific concrete classes.</li> <li>Sub-classes can redefine certain steps of an algorithm without changing its general structure.</li> </ul> <h3 id="applicability">Applicability</h3> <ul> <li>The Template Method can be used to implement parts of an algorithm once and leave it up to the concrete classes to implement the behavior according to their needs.</li> <li>It can be used when code reusability is desired without losing control of the algorithm.</li> </ul> <h3 id="structure">Structure</h3> <p><img src="/assets/images/design-patterns-template-method-example.png" alt="" class="full" /></p> <ul> <li>It presents an abstract class with primitive operations that subclasses define to implement steps of an algorithm.</li> <li>The abstract class implements a template method defining the skeleton of the algorithm</li> <li>The concrete classes implement the primitive operations to be executed in the template method.</li> </ul> <div class="notice--info"> <p>It's worth enforcing that `templateMethod()` should be final, and therefore should not be overridden.</p> </div> <h3 id="consequences">Consequences</h3> <ul> <li>Template Method uses inheritance to vary parts of an algorithm. It may become a problem in the future.</li> <li>It can be an important ally in the development of applications, as it provides a way to separate the variable behavior from the invariable behavior of an application.</li> <li>It also contributes to the implementation of the dependency inversion principle.</li> </ul> <h2 id="practical-example-in-swift">Practical Example in Swift</h2> <p>When creating the UI of a project programatically, i.e. setting up the interface without storyboards or XIBs, we need to perform a few basic steps, such as:</p> <ol> <li>Add the sub view to the view.</li> <li>Setup the constraints.</li> <li>Setup additional configuration.</li> </ol> <p>So far, pretty simple. But these steps need to be implemented in the correct order. In case you try to run a piece of code that sets constraints to a view that has not been added yet, the application crashes, because there’s no view to apply those constraints to.</p> <p>This seems like a good use case for Template Method. So, let’s see how it goes.</p> <h3 id="abstraction">Abstraction</h3> <p>In Swift, we can create an abstract type to hold a blueprint of methods, and make our classes conform to it. This way we favor composition over inheritance, minimising one of the downsides of this pattern. So, we do that by declaring a Protocol.</p> <script src="https://gist.github.com/viniciusml/3dcea7d4f21a236a420883b6cb5140ce.js"></script> <p>Our protocol holds the three basic steps to configure views programmatically, and a fourth method <code class="highlighter-rouge">setupView()</code> that’s going to be out template.</p> <p>So we have the basic structure, but we don’t have our algorithm yet. In order to implement it, we are going to use Protocol Extensions.</p> <blockquote> <p>Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function. - Apple documentation.</p> </blockquote> <p>This is how our extension will look like:</p> <script src="https://gist.github.com/viniciusml/2ce685489df73730a00e6003813d02c1.js"></script> <h3 id="implementation">Implementation</h3> <p>Now we created our algorithm, in the classes that implement this protocol, <code class="highlighter-rouge">setupView()</code> is the only method that needs to be called. The other ones will hold the implementation of the algorithm steps, for example:</p> <script src="https://gist.github.com/viniciusml/b80ccfb245d35dabebaab9ac831b0117.js"></script> <p>The class conforms to the protocol, and configures the steps for the algorithm. And the only method called is our template method.</p> <h2 id="conclusion">Conclusion</h2> <p>So, as we could see, the Template Method allows us to approach a common task that needs to be done routinely, and create an abstraction that reinforces the steps to be executed, as well as the order of execution. Besides that, it becomes a standard in the codebase, facilitating the communication with the team and with new developers.</p> <h2 id="references">References</h2> <p>Design Patterns - Elements of Reusable Object-Oriented Software was written by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (also known as the Gang of Four, or GoF)</p> <p>iOS Course: View code module (in Portuguese) - <a href="https://medium.com/@tpLioy/curso-ios-m%C3%B3dulo-sobre-view-code-af0f6188297b">Article</a></p>Vini Lealviniciusmoreiraleal+blog@gmail.comA template method defines the steps of an algorithm and allows the redefinition of one or more of these steps by subclasses.Continuous Integration (CI) - An Introduction2020-04-20T00:00:00+01:002020-04-20T00:00:00+01:00https://vinileal.com/agile/continuous-integration-intro<p>A software development team can benefit from many methodologies that will save them time and repetitive work. As an example, there is continuous integration, continuous delivery and continuous deployment. Methods and techniques like these represent ways to accelerate the delivery of new versions of the application, and are aligned with the <strong>agile methodologies</strong>.</p> <p>Continuous integration (CI) is a software development practice that aims to make code integration more efficient, through automated builds and tests.</p> <p>In agile methodology, one of the proposals is that the software development process should be carried out with more frequent deliveries.</p> <p>As a consequence, the work required to gather, integrate and test all the code developed by the team in a central repository has also to become more frequent.</p> <p>In the words of <a href="https://martinfowler.com/articles/continuousIntegration.html">Martin Fowler</a>:</p> <blockquote> <p>Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.</p> </blockquote> <p>In this context, Continuous Integration helps to reduce the manual work required in the code integration process. In addition, with test automation, bug fixing work is made easier, ensuring that the software is working after each change.</p> <p>To adopt Continuous Integration, it is essential to use version control tools, such as Gitlab or Github.</p> <p>The process of integrating software continuously is, first of all, a matter of communication, and for that everything must be adequate, with automated tests and automated builds.</p> <blockquote> <p>The one prerequisite for a developer committing to the mainline is that they can correctly build their code. This, of course, includes passing the build tests. As with any commit cycle the developer first updates their working copy to match the mainline, resolves any conflicts with the mainline, then builds on their local machine. If the build passes, then they are free to commit to the mainline. - Martin Fowler</p> </blockquote> <h1 id="tools-for-continuous-integration">Tools for Continuous Integration</h1> <p>With the mentioned steps already implemented, it is time to implement a continuous integration tool. There are several of them, such as Jenkins, TravisCI, CircleCI, Bitrise, etc. Some of them are cloud-based, and others are server-based.</p> <p>Many of them are free for open source projects and easy to configure. Of course, each team must choose the one that better fit their needs. The key to good integration, as seen earlier, is a version control environment, a well-defined workflow, automated builds and tests.</p> <p>The tools for continuous integration come in to make the process simpler, and allows the configuration a wide set of requirements, such as:</p> <ul> <li>The development environment</li> <li>The automated build system</li> <li>The automated code formatting</li> <li>Integration with the version control repository</li> <li>Notification emails (in case of errors)</li> </ul> <h1 id="benefits"><strong>Benefits</strong></h1> <p>For the development team, the integration, delivery and continuous deployment practices allow minimized work, reducing errors and making the software available in shorter cycles.</p> <p>For the business, the main benefit of using these approaches is to decrease the time required to release product updates.</p> <p>In competitive markets, this represents a major advantage for companies that want to quickly meet the demands of their users.</p> <p>In addition, by making new * features * available to users more often, the company has the possibility to make its upgrading cycle more efficient.</p> <h1 id="conclusion"><strong>Conclusion</strong></h1> <p>Continuous integration with automated tools has several benefits, as we have seen. First is that teamwork generates fewer errors, which reduces risks, because as the system is integrated continuously and quickly, errors are also detected at the same speed.</p> <p>The bugs, in this format, do not accumulate, not creating a general problem in the system, because instead of taking a day or a week, the error is detected in hours. Because even if the code is tested, errors can arise upon integration and the sooner the errors are detected, the sooner they will be corrected.</p> <p>If you want more Information on this subject, I recommend the very comprehensive article written by <a href="https://martinfowler.com/articles/continuousIntegration.html">Martin Fowler</a>.</p>Vini Lealviniciusmoreiraleal+blog@gmail.comContinuous integration (CI) is a software development practice that aims to make code integration more efficient, through automated builds and tests.Microinteractions in SwiftUI - Menu Button Animation2020-04-12T00:00:00+01:002020-04-12T00:00:00+01:00https://vinileal.com/tutorial/swiftui/microinteraction/animation/menu-button-swiftui<p>Microinteractions have become increasingly important in a world with a dizzying number of digital platforms and an ocean of content. While microinteractions used to be considered an interesting resource in the early days of digital design, in today’s hypercompetitive digital space they have become a crucial element in the overall user experience.</p> <p>Basically, microinteraction is a particular moment of a user’s interaction with a product in order to complete a specific task. For example, when someone presses a “Like” button (whatever it looks like) and sees that their action produced a feedback - the number has changed, the color of the button has changed or it has become inactive, the text on the button reported that the action was done and so on - this is a case of microinteraction.</p> <p>In this article, I will show you how I implemented a menu button microinteraction in SwiftUI.</p> <p>The idea is to present a menu button with 4 horizontal lines, and, when the user taps on the button, it animates into an ‘x’ shape, to represent the option of closing the menu.</p> <p><img src="/assets/images/menu-swiftui-example.png" alt="" class="full" /></p> <p>I began with an empty project, enabling SwiftUI. Then I created a file with two views, like this:</p> <script src="https://gist.github.com/viniciusml/448223728ad085697b88209e3b928a4a.js"></script> <p>I defined a fixed frame for it, and for my purposes it can be a square shaped button. There’s a state property <code class="highlighter-rouge">isAnimating</code>, that the animations will respond to.</p> <p>For the button body the action is simply to toggle the <code class="highlighter-rouge">isAnimating</code> property, and its label closure calls the <code class="highlighter-rouge">createMenu</code> method. Let’s take a look at it.</p> <script src="https://gist.github.com/viniciusml/ea730fbf13027ce00b0eb4581c82023b.js"></script> <p>There’s a lot going on here, but I’ll break it down. First, the method returns a type eraser view <code class="highlighter-rouge">AnyView</code>, and contains two properties, the <code class="highlighter-rouge">count</code>, which is the number of rows for the button, and the configuration of the menu.</p> <p>In <code class="highlighter-rouge">menu</code> the geometry reader is used, so that we can access the width and height we have available, and, therefore, calculate the properties we need. So, 4 views are grouped, and we calculate <code class="highlighter-rouge">availableHeight</code>, <code class="highlighter-rouge">spacing</code>, <code class="highlighter-rouge">height</code> and <code class="highlighter-rouge">width</code>.</p> <p><img src="/assets/images/menu-swiftui-example-variables.png" alt="" class="full" /></p> <p>Then, the rectangles are created with the height and width, and we can finally configure them. Each rectangle is overlapping the other ones, so we’ll use the <code class="highlighter-rouge">offset</code> modifier and multiply the index by the available height. This way they get positioned correctly along the y axis.</p> <p>Then I configured the animations, which are custom modifiers. I’ll get to them in a second. Finally I used the <code class="highlighter-rouge">animation</code> modifier, with a small delay and the <code class="highlighter-rouge">easeInOut</code> option, and return the menu.</p> <h3 id="configuring-the-animations">Configuring the Animations</h3> <p>The <code class="highlighter-rouge">MiddleMenuRect</code> is a custom modifier that handles the second and third rectangles (index ‘1’ and ‘2’). Both of them need to rotate, on opposite directions.</p> <p>Here’s how the code look like:</p> <script src="https://gist.github.com/viniciusml/7e3185319cc82116f46334a195601ae6.js"></script> <p>In the body function, two modifiers are being called: <code class="highlighter-rouge">rotate</code> and <code class="highlighter-rouge">offset</code>. That’s because when the rect is rotated there’s a slight difference in position, so they need to me adjusted in order to form the ‘x’.</p> <p>The modifiers return a value based on a condition of being the middle indexes and the <code class="highlighter-rouge">isAnimating</code> boolean.</p> <p>For the <code class="highlighter-rouge">MarginMenuRect</code> the setup is very similar, but this time, the first and last indexes are placed as conditions and the modifiers <code class="highlighter-rouge">opacity</code> and <code class="highlighter-rouge">offset</code> are applied. While the rectangles are moved through the ‘x’ axis in different directions, the opacity is reduced, giving the idea that they were ‘removed’. Check out the code:</p> <script src="https://gist.github.com/viniciusml/45f914bd1e607146d040d4249a52aa7b.js"></script> <p>For better readability, the <code class="highlighter-rouge">MiddleMenuRect</code> and the <code class="highlighter-rouge">MarginMenuRect</code> view modifiers were added to an extension:</p> <script src="https://gist.github.com/viniciusml/388fec5b42caaaceedf4bec447197fa9.js"></script> <p>That’s it! We have a nice menu button, that when tapped turns into an ‘x’. Here’s how it looks in action:</p> <p><img src="/assets/images/menu-swiftui-result.gif" alt="" class="full" /></p> <p>Nice, isn’t it?</p> <h3 id="conclusion">Conclusion</h3> <p>Utilising microinteractions can enrich usability. The features of an app attract a user to the product, but the details more then often make a huge difference. This was an example of how a microinteraction can be implemented in SwiftUI and give a nice touch to your apps.</p> <p>Developing it was fun, and it was pleasant to see the animation in place. If you want to see the full code, here’s the <a href="https://gist.github.com/viniciusml/16c14939828521091aabc855dbf69875">gist</a>. Thanks for reading!</p>Vini Lealviniciusmoreiraleal+blog@gmail.comIn this article, I will show you how I implemented a menu button microinteraction in SwiftUI.Test Driving UIPageViewController implementation2020-04-04T00:00:00+01:002020-04-04T00:00:00+01:00https://vinileal.com/tutorial/tdd/tdd-uipageviewcontroller<p>A UIPageViewController is a very popular element in iOS Projects. It’s commonly seen in onboarding screens, but it has a ton of other uses.</p> <p>Me and my friend <a href="https://www.linkedin.com/in/mauro-marques-89910913b/">Mauro Marques</a> are using one for the onboarding screen of our app Hira, and while I was developing the beautiful screens desgined by him, I decided to register the proccess of implementing it using a <strong>Test Driven Development</strong> approach.</p> <p>Just like the name suggests, the entire development is driven by tests. The cycle consists of four steps:</p> <ul> <li>Write a test that is going to fail - (Red)</li> <li>Make the test pass - (Green)</li> <li>Refactor the code</li> <li>Repeat</li> </ul> <p>We’ll begin with an empty project, with an unit test target. I am not going to use storyboards, so I’ll just set the basic configuration to my project by deleting the storyboard. In case you need some help, there’s a quick video, in which Sean Allen demonstrates how to do it <a href="https://www.youtube.com/watch?v=Htn4h51BQsk">here</a>.</p> <p>Now, off to our test driven development. The first and simplest assertion we can make is that the PageViewController is initialised with no controllers (pages).</p> <p>Since <strong>UIPageViewController</strong> has a <code class="highlighter-rouge">viewControllers: Array&lt;UIViewController&gt;</code> property, we can assert that this property is empty.</p> <script src="https://gist.github.com/viniciusml/22294a14ce4913124f3beddabba00b6f.js"></script> <p>Soon enough, the compiler warns us, because we still don’t have a PageViewController. This means we are in the red state (tests not passing or code not compiling), which means we can write production code.</p> <p>Let’s satisfy the compiler by adding the simplest piece of code.</p> <script src="https://gist.github.com/viniciusml/3067b05ab3e314d0858a9caf1deaa8be.js"></script> <p>The errors are gone, and when we run our tests they pass, because by default this property is empty.</p> <p>Since we don’t have anything to refactor, let’s move on to the next test. According to my use case, I need the <code class="highlighter-rouge">.transitionStyle</code> to be of .<code class="highlighter-rouge">scroll</code> type. So, let’s test it. Add the following code to PageViewControllerTests.</p> <script src="https://gist.github.com/viniciusml/b44e1f515abf431cf008cba3d8b2a74a.js"></script> <p>If we run the tests now, they will not pass, because we still need to set this property. Add the following code to PageViewController.</p> <script src="https://gist.github.com/viniciusml/34e108a0f76435e209b5ec0aaaf18004.js"></script> <p>We are using the initialiser to set the property. If we run the tests they will pass.</p> <p>Alright, moving on with the <code class="highlighter-rouge">.navigationOrientation</code>. In this case I’ll need it <code class="highlighter-rouge">.horizontal</code>. Add the following code to PageViewControllerTests.</p> <script src="https://gist.github.com/viniciusml/a373c29f7ba0e0ce8a23a072c7132743.js"></script> <p>If we run it now, it won’t pass, because in the initialiser we added previously was setting the property to <code class="highlighter-rouge">.vertical</code>. So let’s change it to <code class="highlighter-rouge">.horizontal</code>. Now the tests are passing.</p> <p>As a refactoring measure, we can create a helper method in PageViewControllerTests in order to create the SUT, or the <em>system under test</em>. By using a helper method, we concentrate the SUT generation to one single place, and if we need to change or add something in the future, we just need to do it in that single place.</p> <script src="https://gist.github.com/viniciusml/9fab826abdf8db3c38b940de0366c6db.js"></script> <p>Now, replace <code class="highlighter-rouge">PageViewController()</code> by <code class="highlighter-rouge">makeSUT()</code> in the previous tests.</p> <p>Moving on, we need to assert that when the view loads, the method <code class="highlighter-rouge">setViewControllers(_:direction:animated:completion:)</code> is set with the initial view controller. Add this code to PageViewControllerTests</p> <script src="https://gist.github.com/viniciusml/ccb865bf41079d5f53776572a7d11269.js"></script> <p>Here we are testing that <strong>given</strong> at least one controller, <strong>when</strong> the view is loaded, the array of viewControllers is equal to the first item of this array.</p> <p>The code will not compile because we need to make some changes to the <code class="highlighter-rouge">makeSUT()</code> method. Replace the existing method by this following one:</p> <script src="https://gist.github.com/viniciusml/29a4769d69d4410e6efd25e1e4e8942b.js"></script> <p>Here we are passing the controllers to be used as pages into the PageViewController initialiser.</p> <p>So, we also need to change the <code class="highlighter-rouge">init()</code> in PageViewController to:</p> <script src="https://gist.github.com/viniciusml/bb74df4e68d284065e6d8b8965a22836.js"></script> <p>Also, we need to declare the property:</p> <script src="https://gist.github.com/viniciusml/1cd0ec383bb5be11bfbfa41254159ab5.js"></script> <p>Now the code compiles, but the tests are not passing. And that is because we did not implement the method yet. So, add this code to PageViewController.</p> <script src="https://gist.github.com/viniciusml/0cbcd0d9fcdc041f0d98514303753f4e.js"></script> <p>Here, in <code class="highlighter-rouge">viewDidLoad()</code> we check if there’s a first item in the pages array. If so, we call <code class="highlighter-rouge">setViewControllers(_:direction:animated:completion:)</code> with it. Let’s run the tests, and they pass!</p> <p>We can make some refactoring to make our code easier to read, so let’s do it. Replace the <code class="highlighter-rouge">init()</code> and <code class="highlighter-rouge">requiredInit()</code> by this code:</p> <script src="https://gist.github.com/viniciusml/fe8ef01445abaae85275debcb7a8df38.js"></script> <p>We simplified it a bit using a convenience <a href="http://vinileal.com/initialization/basics/swift-initializers/">initialiser</a>. Now, moving on, let’s test the dataSource.</p> <p>We need to make sure that when the user swipes right, the next view controller is called and presented. There is a <code class="highlighter-rouge">UIPageViewDataSource</code> method that handles this, called <code class="highlighter-rouge">pageViewController(_:viewControllerAfter:)</code>.</p> <p>Let’s add the following test:</p> <script src="https://gist.github.com/viniciusml/90bdad7c7dc4688a86f9babe36c3dd54.js"></script> <p>So, given two controllers, when our pageViewController is swiped (which triggers the data source method), we expect that the controller resulting from the <code class="highlighter-rouge">pageViewController(_:viewControllerAfter:)</code> controller1 is the controller2.</p> <p>The tests will not compile yet, because we didn’t implement the dataSource in our production side.</p> <p>Let’s add the <code class="highlighter-rouge">dataSource = self</code> to <code class="highlighter-rouge">viewDidLoad()</code> in PageViewController class.</p> <p>Now we can make an extension to conform to the <code class="highlighter-rouge">UIPageViewControllerDataSource</code>, like so:</p> <script src="https://gist.github.com/viniciusml/9727c7f2bfac7d3ed836f1fd321ea2d9.js"></script> <p>The simplest thing to make the tests pass is to return the second item in the array. But it won’t cover all cases, and let’s see why by adding the next test.</p> <p>Add this to PageViewControllerTests:</p> <script src="https://gist.github.com/viniciusml/b6a6a6462c81451e3d6b6623c28039b5.js"></script> <p>So it’s basic the same setup, but this time we are adding one more controller, and making sure that when <code class="highlighter-rouge">pageViewController(_:viewControllerAfter:)</code> is triggered two times in a row, we get the third controller. The test fails because we hardcoded a value in our production side. Let’s fix this!</p> <p>Add the following code to <code class="highlighter-rouge">PageViewController.pageViewController(_:viewControllerAfter:)</code>:</p> <script src="https://gist.github.com/viniciusml/394718563e164eeb069f96bfc97f70ce.js"></script> <p>Here we are getting the index of current the view controller, adding one to it and return the controller for the new index. Cool, if we run the tests, they pass. Can you spot something to refactor?</p> <p>Yes, let’s do it. We are going to add an <code class="highlighter-rouge">UIPageViewController</code> extension to the same file as PageViewControllerTests, with the following code:</p> <script src="https://gist.github.com/viniciusml/28d673da52277f6cf6da495e9f105606.js"></script> <p>This way, replace occurrences of <code class="highlighter-rouge">sut.dataSource?.pageViewController(sut, viewControllerAfter: controller1)</code> by <code class="highlighter-rouge">sut.controllerAfter(controller1)</code>.</p> <p>Alright, we covered the situation of getting the next index, but we are still missing a scenario. When the maximum number of pages is reached, what should happen?</p> <p>According to my use case, when the last controller is reached, if the user swipes right, nothing should happen, so let’s test it.</p> <p>Add this to PageViewControllerTests class:</p> <script src="https://gist.github.com/viniciusml/c7b9e5a9ac0ad4964839f8fb6db87b75.js"></script> <p>So we are asserting that when the maximum number of pages is reached, if an attempt to swipe is made, the method returns <code class="highlighter-rouge">nil</code>, otherwise we could have a runtime <em>index out of range error.</em></p> <p>By running the tests, we see that this one doesn’t pass. But to make it pass its simple, we add the following code just before the return in <code class="highlighter-rouge">pageViewController(_:viewControllerAfter:)</code>:</p> <script src="https://gist.github.com/viniciusml/fb7a4f6fddb1d5c78678c5ee518c3b32.js"></script> <p>Alright, tests are passing again. Moving on!</p> <p>We are going to test the opposite scenario now, which is the swipe left in this case. We’ll start by adding this test:</p> <script src="https://gist.github.com/viniciusml/a5acebf87244fb9a7789a0bd5b2fab05.js"></script> <p>And let’s also add the extension for the controllerBefore helper method:</p> <script src="https://gist.github.com/viniciusml/aadb7f285a87f0c1e6ced28a046891e4.js"></script> <p>So, when the page controller is displaying the first page, if a left swipe is attempted, the method should return <code class="highlighter-rouge">nil</code>. If we run, it passes, because of the hardcoded <code class="highlighter-rouge">nil</code> we returned when we implemented the <code class="highlighter-rouge">UIPageViewControllerDataSource</code> protocol.</p> <p>Let’s move on to the next test.</p> <script src="https://gist.github.com/viniciusml/fd081fce83a95f784045d1966328f31d.js"></script> <p>It’s pretty much the same situation we tested with <code class="highlighter-rouge">pageViewController(_:viewControllerAfter:)</code>, but this time, we are expecting to have the previous controller. If we run the tests, this one fails, so let’s implement our code.</p> <p>In <code class="highlighter-rouge">PageViewController.pageViewController(_:viewControllerBefore:)</code>, replace the return <code class="highlighter-rouge">nil</code> by the following:</p> <script src="https://gist.github.com/viniciusml/5b8692b1e8d32e9b329d3cb355b2f5ac.js"></script> <p>Again, we get the index of current controller, subtract one, check if it’s not smaller then zero, and return the corresponding controller to the index. Let’s run the tests and see that they pass!</p> <p>Now, just to make sure we have the correct behaviour, let’s add the following test:</p> <script src="https://gist.github.com/viniciusml/183dac213e14d8d026f2227267b646b9.js"></script> <p>So, if we are in the third controller, and perform swipe left twice, we should get the first controller, correct? Yes, and our tests are showing us that!</p> <p>Now we tested the basic structure, we’ll move on to the <code class="highlighter-rouge">UIPageControl</code>. We need a page control, and we can get it for ‘free’.</p> <h3 id="apples-documentation-says">Apple’s documentation says:</h3> <blockquote> <p>If both of the methods in ‘Supporting a Page Indicator’ are implemented and the page view controller’s transition style is UIPageViewController.TransitionStyle.scroll, a page indicator is visible.</p> </blockquote> <p>Right, our transition style is <code class="highlighter-rouge">.scroll</code>, so we need to implement the methods:</p> <ul> <li><code class="highlighter-rouge">presentationCount(for:)</code></li> <li><code class="highlighter-rouge">presentationIndex(for:)</code></li> </ul> <p>Let’s test that we are setting the correct presentation count.</p> <script src="https://gist.github.com/viniciusml/76ce953b0e0d44d37bb08cbfa0abf8ef.js"></script> <p>So when we initialise the PageViewController with a certain number of pages, we expect the <code class="highlighter-rouge">presentationCount</code> to be equal to the number of pages. And we check that by calling a dataSource method <code class="highlighter-rouge">presentationCount(for:)</code>.</p> <p>If we run it, it fails. Because we didn’t implement it yet. So let’s fix this by adding it to our <code class="highlighter-rouge">UIPageViewControllerDataSource</code> extension:</p> <script src="https://gist.github.com/viniciusml/8dcc9009ebd0535fece594bdcba6ac1a.js"></script> <p>We are returning the number of items in pages array, because we want the number of indicators in <code class="highlighter-rouge">UIPageControl</code> to be the same as the number of pages. We run the tests, and they pass. Nice!</p> <p>Now, the other required method for setting the <code class="highlighter-rouge">UIPageControl</code> is <code class="highlighter-rouge">presentationIndex(for:)</code>. Let’s add the following test:</p> <script src="https://gist.github.com/viniciusml/cdd0bb02ace23b92401b116e20e15e5d.js"></script> <p>Now we expect that when we initialise PageViewController, that <code class="highlighter-rouge">presentationIndex</code> is set to zero, i.e. the first page. We run the tests and this one fails, because we don’t have that method yet. Add this to the dataSource extension:</p> <script src="https://gist.github.com/viniciusml/8a0b19c78eceb5f14ca251691d763894.js"></script> <p>So, when we run the tests, they pass. Great!</p> <p>We added a hardcoded ‘0’ there, but it may be better to replace it by a variable, just in case we may need to use set a value in the future. Go on and declare the variable at the top of the file:</p> <script src="https://gist.github.com/viniciusml/a5e5bacde7ecf3eeab546234e42d7754.js"></script> <p>And replace the ‘0’ by <code class="highlighter-rouge">pageControlIndex</code>.</p> <p>Great, we implemented the tests, they are passing, now it’s time to see our pageViewController in action. Add the following method to your SceneDelegate class:</p> <script src="https://gist.github.com/viniciusml/f9988a9a47e74e59c36405aac9b1940a.js"></script> <p>And add this to <code class="highlighter-rouge">scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)</code>:</p> <script src="https://gist.github.com/viniciusml/da3f717fdff81f0edd2bd3f45ef1b75d.js"></script> <p>Since we are not using storyboards, this code prepares the window, and set’s a <code class="highlighter-rouge">rootViewController</code> to it. Our <code class="highlighter-rouge">rootViewController</code>, in this case, is our PageViewController, with 6 pages, each one with a different background color.</p> <p>Hit <strong>command + R</strong> and let’s see it in action!</p> <p><img src="/assets/images/uipagecontroller-example.gif" alt="" class="full" /></p> <p>Very nice, isn’t it? Now that the behaviour is covered, it’s just a matter of setting a nice UI and some cool animations and deliver a nice page control.</p> <p>If you want you can check the full code <a href="https://github.com/viniciusml/blog-Source.git">here</a>.</p> <p>This was a glimpse of TDD. It’s a really powerful methodology to write maintainable and reliable code.</p> <p>Thanks for reading, if you have any questions leave it in the comments below!</p>Vini Lealviniciusmoreiraleal+blog@gmail.comIn this article, I'll show you a way to implement an UIPageViewController using a Test Driven Development approach.Code Reviews2020-03-27T00:00:00+00:002020-03-27T00:00:00+00:00https://vinileal.com/productivity/basics/code-reviews<p><strong>How can you improve your team’s productivity with code reviews?</strong></p> <p>There are quite a few things in life that you only truly see the importance after experiencing, and code reviews are definitely one of those. By talking to my colleagues who apply it frequently in their workflow I could see that it improves a lot the efficiency of the team, but at the same time, talking with the colleagues who had never used it before (including me) it’s hard to identify the value of this tool.</p> <p>In a <strong>code review,</strong> basically, after a developer finishes writing a new piece of code (it can be a new feature, a bug fix, anything), another developer checks the code and covers some questions that may vary according to the company’s standards. A few examples are:</p> <ul> <li>Can the logic of the code be improved? Does it cover all cases proposed?</li> <li>Are all requirements implemented?</li> <li>Does the new code conform with the company’s guidelines?</li> <li>Are the tests enough for the new code or do they need to be modified?</li> </ul> <p>Well, clearly there are benefits, and lots of them. So it might be good giving it a try and evaluate if it suits the team’s needs and if it fits their style style.</p> <h2 id="how-to-begin">How to begin</h2> <p>The first step, in my opinion, should be proposing it to the team. In this moment, the benefits of this practice can be explained to the team, such as:</p> <ul> <li>It facilitates knowledge across everyone in the team, which means that all members know what’s going on with the code base.</li> <li>Helps to establish or reinforce coding standards.</li> <li>It’s a wonderful tool to onboard new developers. By having their code reviewed, new developers can learn quickly about the guidelines, and easily adapt in conversations regarding the code. Also, by reviewing veteran’s, new developers can contribute with a fresh pair of eyes, which often helps a team to tackle a problem in a different way.</li> <li>Code reviews produce software with fewer defects.</li> <li>Ensures that necessary documentation is being written.</li> </ul> <h2 id="the-time-issue">The time issue</h2> <p>Some of the most popular counterargument used by developers new to code reviews are the time spent to do it. Indeed, it’s an additional step into the development process, which means it takes some time. But it’s not time wasted and there are some ways to make sure it’s optimised.</p> <ul> <li>Review before merging. Sounds a bit obvious, but it can help discover mistakes and improve the code before it reaches the development branch.</li> <li>Set an appropriate timeframe to perform the reviews. Eg.: no more then one hour.</li> </ul> <p>Now, when it comes to introducing this practice into the development process, there are is a key aspect that may help: <strong>starting slowly</strong>. Sometimes, working in a fast paced environment, means thats one needs to be very thoughtful in this part, because the introduction of a new step might be slow in the beginning.</p> <p>It can be useful to begin by implementing pull requests after small tasks were done, just to get the hang of it, and after some time evolve into reviewing bigger tasks until the point where the whole team is comfortable with it, in which reviews can be performed for every new code written for production.</p> <h2 id="a-few-tips-to-take-the-most-out-of-code-reviews">A few tips to take the most out of code reviews</h2> <ul> <li>Begin the review with a fresh mind and without any expectations on what the code should be like.</li> <li>Review your own code before submitting it to review. It may sound as basic advice, but you may find some things to improve.</li> <li>If there are special places where you want feedback, make them explicit.</li> <li>In case there’s something not very clear, ask questions to the author.</li> <li>Explain why there’s room for improvement in the code reviewed and if possible, propose a solution.</li> </ul> <h2 id="veredict">Veredict</h2> <p>Code reviews are relatively simple to include in the workflow, and can greatly improve software quality.</p> <p>Depending on your team, it can good fit, and although it may bring some changes in the process, the benefits for sure outweigh the cost of adaptation.</p> <p>It is something that combines technical and non-technical skills, and, as most of things in life, the more you do it, the more you get better at it. It is super important to be open to feedback and being able to offer proper feedback as well.</p> <p>What are your thoughts on this? Do you do code reviews in your team?</p>Vini Lealviniciusmoreiraleal+blog@gmail.comHow can you improve your team’s productivity with code reviews?