Classes, Jim, but not as we know them (Simon Peyton Jones)
Haskell is a statically typed, purely functional language that was designed 20 years ago by a committee of academics to be a research language. Most new programming languages never catch on and die after about a year having only ever had one user. Succesful research languages live somewhere in between five to ten years having up to a hundred users. Truly succesful languages don’t die out at all and accumulate millions of users. Examples of this would be C++, Java, Perl and Ruby. On the other side of the spectrum are committee languages, that never have any users at all. Haskell on the other hand seems to defy this category. After about five years it had a couple thousand users and at the moment this number even seems to grow to tens of thousands. According to langpop.com it is hardly ever used, but on the contrary it is one of the most talked about languages. This popularity can be traced back to some good ideas like purely functional, controlling effects, laziness, concurrency and parallelism, domain specific embedded languages, sexy types in general and type classes in particular. As you can pass functions into Haskell functions, how can you make a general equals method that works no matter what arguments you pass into it? Unsatisfactory solutions are local choice or to have the function work for everything except functions. To solve this problem, Haskell has introduced type classes. A type class is an indication of the type of argument you expect: this function works for any type ‘a’, provided ‘a’ is an instance of class ‘X’. For every type class, there is a class definition that says what the operations for that type class are. Then an instance declaration for a type T says how the operations of that typeclass are implemented on T’s. All this scales up nicely, allowing you to build big overloaded functions by calling smaller overloaded functions, and building big instances by building on smaller instances. Even literals can be overloaded, allowing 1 to mean fromInteger 1. Type classes have proved extraordinarily convenient in practice for cases like equality, ordering, serialisation, numerical operations, monadic operations and much more. Comparing type classes and object-oriented programming, it must be noted that type classes use type-based dispatching, instead of value-based dispatching. A Haskell class is more like an OO interface than a class, as it says what operations the type must support. The advantage of typeclasses over interfaces is that existing types can retroactively be made instances of a new type class. Haskell on the other hand has no sub-typing, so if one of the arguments of a function is a Tree, then it must be exactly a Tree, and nothing else. The ability to act on arguments of various types can only be achieved via type classes, which means that you must anticipate the need to act on arguments of various types.
Agile modeling and documentation best practices (Scott Ambler)
Agile modeling is a collection of practices based on several values and proven software engineering principles. The models this produces are as simple as possible so they are still understandable and can fulfill their purpose, but also so that they are just barely enough. When trying to scale agile delivery suddenly a lot of factors come into play like team size, compliance requirements, geographical distribution, enterprise discipline, technical complexity and organizational complexity. Agile Model Driven Development tries to address these issues. AMDD starts each project with iteration zero where the intial requirements and the initial architecture are envisioned. This should take a few days at most. Then every iteration starts with iteration modeling, which should take a few hours at most. This modeling is necessary to plan the iteration. When the resulting model isn’t specific enough for certain issues, this is followed up with just in time model storming, which should take a few minutes at most. And this in turn is followed by Test Driven Development. All of this modeling takes place under the assumptions that it is only just barely good enough and that it happens as late as possible so you can document stable things and not speculations that will prove false. You should prefer executable specifications over static documentation, as static documentation has a tendency not to be maintained. As for the quantity, you need a bit more than the extremists may care to admit, but a lot less than the bureaucrats realize. A big problem with documentation in most organizations is that it isn’t very effective, as the chance that it is correct, read, understood, followed and trusted are ever decreasing respectively. So in conclusion it should be realized that a model isn’t necessarily a document, that modeling is a key scaling strategy for agile development projects, and also an important part of every software process (including agile ones), and it’s an important communication technique. You’re likely doing a lot more modeling than you realize, but as you don’t realize you’re doing it, you could be a lot better at it.
Adventures of an Agile Architect (Dan North)
Once upon a time there was an agile architect named Dan. He was asked to coach a non-agile team into being agile. When he arrived he found that technically the software was SOA gone bad. All sorts of clients were coupled to all sorts of services through a WSDL. There was a whole lot of duplication too, as lots of the services did basically the same thing, but using different parameters. Operationally it was a complex, flaky infrastructure, with lots of EJB’s running in a non-standard old version of JBoss. And finally organisationally, the developers lived in silos, arguing vehemently for their prefered solutions, without listening to each other. The story has a happy ending however, as he was able to guide them into implementing a SOA as it was meant to be with clear context boundaries. Operationally they ended up with deterministic deployments and a product that was stable in production. And organisationally they had a happy team that staid happy even after he left. But before he got there, he set out to listen to all the developers. And was blown away by the realization that they all wanted the same thing. This made it a lost easier to determine and set a strategy. He warned the management that he was about to change things to remedy the situation and that it would make a lot of noise. They agreed on the condition that he really would fix things. He then set off to change the culture. It turned out that daily standups had already been tried, but that they had failed to be effective. Instead he set out to have a daily discussion about what the best possible today could be. With this and similar measures he was able to get the whole team on board to set off to become agile. To fix the technical mess the software was in, he introduced the command pattern. And when they chose a wrong direction in the implementation of said pattern he found out after taking the blame for that mistake that the team was now more willing to start experimenting, as nothing had happened to Dan after admitting the mistake. After the command pattern was in place they got rid of the EJB’s as they really didn’t need them. When the EJB’s were finally gone they introduced bounded contexts to separate the different areas in the software. This resulted in the fact that every piece of the code now had a logical place where it could be found. And when all this had been done they opened up their code to other teams and spread their way of working throughout the company. The lessons Dan learned from this project, are the ones he told me and the same as I’m going to tell you now. First of all, there is always a reason why the organisation and the software are in the state they are in. A lot of choices have preceded the endresult, choices that were most likely the best possible choices that could have been taken at the moment. Second, in order to make everyone aware of those reasons, every team should have a shaman that can tell the stories with that history. If a team doesn’t have a shaman, you should either find one, or learn how to be a shaman yourself. The third lesson was to strip away everything you can, right until the moment that it breaks (at which time you have to put the last bit back). Superfluous code obfuscates the story of the code and makes it much harder to understand. The fourth lesson was that you can’t buy architecture. You can buy tools if necessary, but architecture has to be made to fit the situtation. Trying to hammer your situation into an existing architecture results in bad code and an unhappy team. The fifth lesson was to use transitional architectures. Sometimes a piece of code is too complex to be changed all at once. Transitional architectures are architectures that are far from perfect, but that are a step in the right direction. You should take care to communicate to the rest of the team that this is only a single step, and where you intend to go. And the final, and perhaps the hardest, lesson was that life moves on. When you leave a team they’ll probably make decisions you wouldn’t have made and that you might not agree with, but that are the best they could make.
Kanban vs and Scrum – Making the most of both (Henrik Kniberg)
Scrum in a nutshell is to split the product, the organiztion and the time to go from a large group spending a long time building a huge thing to a small team spending a little time building a small thing but integrating regularly to see the whole. A typical evolution from waterfall to Scrum goes through the ScrumButt phase. Kanban in a nutshell is to visualize the workflow, limit the work in progress and to measure and optimize said flow. A typical Scrum to Kanban evolution is caused by the fact that for most Operations & Support teams, Scrum doesn’t fit properly and so they evolve to Kanban. Scrum and Kanban are both tools, and like a knife and a fork, it’s hard to say which is best, they are simply intended for different purposes. A comparison should therefor be made to understand them better, not to judge which is best. Scrum prescribes 3 roles, whereas Kanban knows no roles. Scrum prescribes timeboxed iterations, whereas Kanban does not. Both limit work in progress (WIP), but in different ways. Scrum limits the WIP per unit of time (iteration), whereas Kanban limits the WIP per workflow state. Both are empirical, but Kanban is more configurable. Scrum discourages change in mid-iteration, making users wait until the next sprint, whereas with Kanban the user only has to wait until a slot in a certain workflow state becomes available. A Scrum board is reset between iterations, whereas a Kanban board never gets reset.
Turning on a Sixpence – No excuses: Concept to cash every week (Kris Lander & Gus Power)
(Summary taken from the handouts that could be downloaded on above blog)
KEEP IT MOVING: We pursue profit for our clients by continuously delivering features in response to market and user feedback.
KEEP IT WORKING: We take a balanced approach, getting feedback all the time, building quality in and managing technical debt carefully, to move at speed and keep the cost of change low.
KEEP IT TOGETHER: We keep software fully integrated and in a deployable state by checking in every hour or so and getting quick confirmation that everything is working from our builds.
KEEP IT REAL: We keep software grounded in the real world by looking after our own environments, configuring them and optimizing them as part of the whole product.
KEEP IT COMING: We deliver software at a sustainable pace and work towards a visible destination, planning just enough just in time and keeping options open for as long as possible, so we can maximize return for our clients.
Typical Java Problems in the Wild (Eberhard Wolff)
Some common problems keep cropping up in Java code. Ten of these were presented by Eberhard Wolff. They were not necessarily the most common, but certainly with severe effects.
#1 Weak transaction handling.
The transaction is committed, but the exceptions that might occur are never caught, and no rollback is performed. This kind of problem is hard to detect as it only has effects if an exception is thrown. But when it does occur, it can lead to weird behavior and data loss and many other strange effects. Possible solutions are declarative transactions and transaction templates.
#2 Exception design
The three rules “Get all the details from a system exception!”, “Each layer must only use its own exceptions!” and “Exceptions have to be checked – then they must be handled and the code is more secure.” sound reasonable but lead to lots of useless exception handling code and lots of exception types without specific handling of that type. Possible solutions for this are to use more unchecked exceptions (RuntimeExceptions) and to handle only cases you really want to handle. This should be augmented with generic exception handling in the web layer that handles all runtime exceptions that were not handled elsewhere.
#3 Exception handling
Many exceptions are not logged or even swallowed entirely. This is related to #2, if you have excessive checked exceptions, this will occur more often as developers are forced to handle exceptions they can’t really handle. The solution is to at least log exceptions, and to think twice on whether it really is okay to continue in the specific situation. This should be combined with generic handling and improving the exception design.
#4 Architecture mess
Architecture is the decomposition of systems into parts. You should take care not to have overly large or complex parts and you certainly don’t want cyclic dependencies. Because if you do, maintenance will be hard as will concurrent development. Changes will in such a case often have unforeseeable results. Solving this is very hard if you are already in such a mess. So make sure to manage dependencies from the start. Otherwise you are looking at a major restructuring of your application.
#5 Adaptor layer
When performing a service you often encounter cross-cutting concerns such as security, tracing, checking for null arguments, logging, conversions from DTO to internal representations. This kind of code adds lots of boilerplate to each service. Changes to any of these items is very hard, because there are a lot of methods to change. The solution is to use aspects to take care of these cross-cutting concerns.
#6 No DAO
Quite a few people think that as the JPA is a standard, it doesn’t need abstracting away from. But this means that the service will be dependant on JDBC and will throw SQLException, meaning that the persistance will be visible i nthe service layer and beyond. This results in code that is impossible to test without a database, so no real unit tests are possible. The solution is to use a DAO or a repository.
#7 No tests or bad tests
Having no test at all or bad tests means that the code is not properly tested and most likely of low quality. This leads to the code being hard to change. The solution, of course, is to write proper unit tests. But reality has shown that writing proper tests is hard. Therefor you need to educate people on how to do it. Tests should also be integrated into automatic builds. And integration tests and functionality tests should be added as well.
#8 Creating SQL statements
Creating SQL statements by simply concatenating string with parameters is bad for performance, as the statement is parsed every time. Even worse is that this leaves your software open to SQL injection. The solution is to use preparedstatements.
#9 Not designing for performance
If performance is left for the final stages of development, then you can hardly do anything to fix it. As changes might introduce functional errors and it’s too late for the bigger that are necessary. Even worse, the results might be wrong if the performance test is run on different hardware than production. The solution is to get information about the performance requirements before starting on development.
#10 Multiple threads, memory leaks
If multi-threading isn’t done properly, then the system will work in small tests, but production will fail. The problems will probably be hard to analyze and/or fix and they can only be found by code reviews or extensive debugging using thread dumps. The solution is to use WeakHashMap to avoid memory leaks, to synchronize, and to prefer local variables. ConcurrentHashMap should also be considered.