This was a second Craft Conf for some of my colleagues, and this year I took their word, and joined the event for the first time. I’m going to write down some of my impressions, so it might be easier to decide on putting it on your calendar for the next year.
Saturday, April 30, 2016
Saturday, March 26, 2016
On why we test (code)
I’m not a great programmer; I’m just a good programmer with great habits.
Last week I had a talk with our lead software testing engineer, on multiple aspects of what quality in software development means. Even though it is just a cog in the grand scheme of quality assurance, maintainability of the code base strikes me as one of those aspects for which the responsibility is entirely on developers. Automatic tests, refactoring and diligence of the code reviewers are the only safeguards of the code quality. Other team members, testers and managers, will not be able to help us and some will through external pressure (deadlines and such) inadvertently contribute to its decay. This brings us to the subject of…
Legacy codeMichael Feathers introduced a definition of legacy code as code without tests. When present and adequate, tests give us the confidence to make changes to the code without fear of regression (breaking something which worked). You can only fully appreciate this if you maintained a code base written by someone else (quite possibly a group of people which is not available to you) over several years. The key problem of legacy code is that it was never designed to be testable. So before writing our safety net of unit tests, we need to refactor the code to make it more testable. However, in order to refactor safely, we must have unit tests to verify that we haven’t broken anything while making changes…
Advice and techniques on how to deal with it, you can find in Michael’s book Working Effectively with Legacy Code.
I will be focusing more on how not to write legacy code.
Test firstThis is a well known technique of the practitioners of the TDD. The first step is writing a failing test. Yes, you write test before you write the production code. Why the f… would I do that?! – Because of the proper focus. Before you start coding, you can actually focus on the task your code needs to do. Getting invested with the technical details of the implementation may impair your vision of the place and purpose of the new code. Testing first will give you a perspective of how your code will be seen from outside and how it fits and collaborates with its surroundings. Writing the tests after usually means confirming that the code does what you wrote it to do. This is a valid goal itself. However, we may be missing the insight we get while thinking about the problem from ‘client’ perspective. This insight could be integrated in the design and implementation of the solution. Other danger is that being invested in the solution, one might tend to compromise the quality and role of the tests, as being seen as something which just confirms something we already know (that our solution is good and it works).
One of my managers asked me once :
– How many bugs did you find with the unit tests?
– None – unit tests are there to prevent bugs from ever entering the production code.
Testable codeBeing able to produce good tests means that:
- You understand the problem you are trying to solve
- You have a good understanding of how your code needs to interact with other parts of the system
- You will produce a testable design
– To a point. From my experience, being able to produce the testable code most often dictates:
- You have removed tight coupling where it is inappropriate
- You have reduced the complexity enough be able to cover all relevant states and behaviors of your code to prove it is working as designed
- I will add stuff to this list as it comes to me
Sunday, March 13, 2016
The new paradigm
Swift and Scala are new generation languages, and represent the contemporary trend of combining the elements of object-oriented and functional programming. Since concepts of object-oriented programming are supported, programmers can still carry on doing business as usual. By doing so, they will, however, fail to utilize great features offered by these languages.
Just as many of the modern languages take over the burden of memory management, freeing the developer to think and code on higher level of abstraction, modern functional tools are freeing us up from dealing with low level implementation details of many mundane tasks. This allows programmers to focus on tasks which add value to customers.
Ceding the control over details
OO makes code understandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts.– Michael Feathers
Complexity is the source of many problems in programming. Quite often we are faced with concepts on different levels of abstraction within one unit; business logic intertwined with implementation details of displaying, storing, sending the data… This complexity is what Feathers refers to as moving parts. Problem quite often manifests itself by not being able to see the big picture from the noise of details.
Object-oriented paradigm is based on encapsulation – hiding the implementation details inside of a unit (class) and exposing the functionality through public interface on higher level of abstraction. In other words, developer lets the rest of the system interact with his/her code through interface defined in terms and on level of abstraction appropriate to the collaboration, ideally without disclosing the implementation details.
Modern functional languages, on the other hand, reduce the amount of implementation details by offering a set of tools which efficiently replace them. Primarily, these are the tools for working with collections, using the higher-order functions. In the imperative approach, which is common for structured and object oriented programming, developer would iterate through collection in some sort of a loop ( often a several nested ones), and apply some operations on its elements. Internal states are often introduced to optimize the process. This allows for faster response, but increase complexity and present a nightmare for introducing the parallelism through multi-threading.
Modern functional tools support declarative approach; they come with built-in optimization tools, which do not require for developer to introduce the additional structures and internal states. This promotes using constants wherever possible instead of variables, which reduces complexity and unforeseen side effects, especially in a multi-threaded environment.
Even if you don’t feel the need to change the language and habits, it is inevitable that these concepts will become a part of all mainstream languages. Apple is going to make the Swift its default language sooner or later. On the other side of the field, some functional concepts are making their way into mainstream JVM scene through Java 8. Scala, even though not yet a mainstream language, is a popular JVM language, very close in syntax and concepts to Swift, with many powerful elements. As such it is a great way to introduce yourself to functional programming paradigm.My recommendation is that if you are already doing iOS development, dive into functional programming using Swift. As Java programmer you have 2 options: Scala and Java 8. Scala is more complex, yet more powerful and expressive language. On the other hand, Java 8 allows the functional concepts to be applied smoothly and without major changes into the existing projects which allow using the latest version of the JVM.