Showing posts with label Agile. Show all posts
Showing posts with label Agile. Show all posts

Tuesday, 3 May 2016

Agile is dead

This is an excellent post, though some might consider it a rant, about how Agile wasn't really nor became what Agile should it should have...

Agile is Dead

"Are you an IT consultant or contractor? Agile Software Development work is dead. If you practice that, you are a doorstop. If you manage that way, you are a boat-anchor. The wave has ended, it is over, and if you went for the head-fake and bought certifications, you wasted some money. Soon recruiters will be putting your resume in the circular storage container. I have been warning you for some time, and the day is here. Hah, you should have listened. Move along."

But here's the best quote:

The moral of this part of the story is that if you produce some compact politicised ideology (manifesto) consisting of principles and rules there will be unintended consequences.  Success creates a religion or cult, and defeat is being ignored.  No such doctrine is perfect.  Thinking you will change the world with a manifesto is naive, and if you succeed you may not have improved the world.

To me, given the problems that Privacy by Design has caused with privacy officers believing in some mythical "compliance" without any consideration of the software engineering or cultural aspects of developing information systems, this sums it up quite nicely!

Friday, 20 November 2015

ABCDE....DevOps and Privacy, pt 2

Earlier I introduced the idea that DevOps, particularly in the area of privacy could take lessons from trauma medicine, particularly in taking on board ideas from ATLS.

This led to some further ideas about the relationships or analogies between disciplines - something we've already discussed before in the context of surgery, aviation and checklists.

As software engineering is being brought closer and closer to the metaphorical coal-face - we've moved away from requirements up-front to agile and now to "DevOps" where engineering and operations become the same thing we are starting to see the need to move to much more structured and disciplined teams of engineers. If this isn't happening then there are some serious cultural and management problems.

As this shift happens we have to develop techniques to deal with this - as already mentioned checklists and ATLS provide the necessary kind of structures.

By why ATLS in particular? Well, we can draw an analogy between DevOps and trauma medicine in that DevOps operates with extremely short time-scales and in an environment where fixes and patches need to be very quick and leave the system in a stable state where a longer-term patch can be made later.

DevOps is the ER of the software engineering world.

Tuesday, 17 February 2015

IWPE2015 Keynote

I'm giving the keynote speech at IWPE2015 which is provisionally entitled

"Engineering Privacy as a Safety-Critical Concern"

I'll talk about some tools and techniques which we can use from other domains such as aviation and medicine and how privacy in software engineering is synonymous with safety in these other domains.

Conference details can be found from an earlier posting or via the link above. Conference date is 21st May 2015 and it will be held in conjunction with the 36th IEEE Symposium on Security and Privacy in San Jose, California.

Wednesday, 19 February 2014

Privacy Engineering and Checklists

A colleague brought to my attention a publication from the PbD community on the subject of privacy engineering [1]. Overall the paper I think gives a good introduction into what privacy engineering could be. I say "could by" because PE needs a huge amount of work, from all angles including the deeper mathematical basis as well as basic, software engineering, process, management etc. The current definition given above is:
"...privacy engineering is the discipline of understanding how to include privacy as a non-functional requirement in systems engineering. While privacy may also appear as a functional requirement of a given system (such as the TOR anonymity system), for most systems, privacy is ancillary to the primary purpose
of the system."
Not bad but quite a few of these non-functional requirements become very awkward functional requirements very quickly as the development proceeds.

The part that particular interests me is regarding checklists:
"The checklist approach to privacy protection has been debated. Checklists have become important safety elements in airplane and medical procedures and are quite common in security auditing. However, their utility for privacy remains questionable. It might be possible to design privacy checklists for frequent and standardized use cases, but the breadth of potential projects makes a standard checklist for everything an unlikely tool."
The above cites an earlier article on this blog about moments that changed how particular industries approached safety. There exists possibly a better article on checklists which explains the rationale behind their use.

Partly the paragraph is correct, the utility of checklists in privacy needs to be established, but, given what a checklist is and what is should be designed to achieve is independent of the area. Indeed the next statement that it might be possible to design privacy checklists for frequent and standardised use cases is exactly the cases where checklists do come into their own. Often repeated, critical phases of design - patterns if you like - are the areas where mistakes are frequently made; things are forgotten etc.

There are NO standard checklists - at least not for the expected usages hinted in the paper. If we compare with the WHO surgical checklists which work in similar, very open, high volatility environments there is a capitalised statement on the bottom of the checklist:
THIS CHECKLIST IS NOT INTENDED TO BE COMPREHENSIVE. ADDITIONS AND MODIFICATIONS TO FIT LOCAL PRACTICE ARE ENCOURAGED.
Ignore at your peril.

Indeed the checklist in privacy WILL NOT give you a standardised approach NOR will it give you the tool for checking your system. It WILL give you a list of things that you should remember to complete at particular relevant points. A checklist should be independent of your processes and partially independent of what ever tooling and techniques are being applied to the problem at hand. Furthermore, if the various items on a checklist are not completed it is not an indication that the process can not continue but rather a warning that important facts might not have been established.

For example, on aircraft take-off there is a checklist item for the setting of flaps. This item may not necessarily specify the specific flap settings as this might vary by many conditions and the item can be ignored (and the flaps not set) and take-off can proceed - though this might be a particularly bad idea as in the Spanair Flight 5022 case.

Interestingly in the paper checkilsts seem to be positioned against privacy impact assessments. I could better imagine that in the privacy checklist an entry "PIAs performed" is included, possibly with further qualifications as necessary. It might be considered that such an entry is superfluous - who would forget to do the PIAs? I agree, pilots would never forget to lower flaps prior to take-off or a surgeon forget to check that the he is set up for the correct procedure to be performed....

Maybe the term checklist isn't the best and this is where some confusion arises. At Great Ormond Street hospital the term "Aide-Mémoire" is used to reflect the function of the checklist and avoid the confusion with the "tick-box mentality" and confusion with process.

Privacy is a very wide area without well established and standardised use cases or at least not at the level of detail that say aviation is as is pointed out in the paper we lack. Indeed it is this lack of standardisation that makes the integration of checklists or aide-mémoires much more important.

Some of our experiences with checklists in this area can be found in an earlier posting entitled: Flying Planes, Surgey and Privacy. [2]


References

[1] Shapiro, Cronk, Cavoukian (2014) Privacy Engineering: Proactively Embedding Privacy, by Design.

[2] Ian Oliver, Tomi Kulmala (2013) Flying planes, Surgery and Privacy.


Thursday, 23 January 2014

On being formal, and possibly agile too...

Way back in my past I used to research formal methods for software engineering. Actually I still do, though now most of my time is actually using formal methods to make better software.

Formal methods are nothing more than a collection of languages and techniques for modifying and reasoning about things (models) written in those languages. Some of these techniques encompass how the process of building a system is made. Herein lies one of the first problems encountered by formal methods practitioners and that is the almost constant challenge from some, such as many in the agile community, that seem to be religiously against any form of modelling.

To those who believe that code is the only deliverable and the only thing that matters, well, C++, C, Fortran, Clojure etc are all formal languages, and you're probably using many of the techniques from formal methods right now as your write your code.

Language such as B, Alloy, Z, VDM etc do is provide a method of expressing a model without worrying about certain, awkward details of their implementation or execution.

Indeed what is happening here is that we have languages and techniques that allow you to concentrate on reasoning and thinking about the problem you are trying to solve without getting bogged down in the details of the final implementation.

If your first worry is the implementation language, or the operating system, or which libraries to use, etc, then you're most certainly not solving the problem.

At Nokia we had some very great successes using formal methods in an agile manner for the development of a semantic web infrastructure for the "Internet of Things". Concentrating on what the system had to do and then later worrying about how it was implemented meant that when it did come to the time we needed to architect the components and decide on specific implementation issues we already knew how the system was going to work, what tests we would need to run and what the expected answers were going to be.
Indeed, many of the tests were little more than checking that the code behaved the same as our earlier models - regression testing if you like.

This resulted in a huge decrease in the time spent in coding and the effective removal of nearly all (logic) bugs before even the beta releases. In fact most of the bugs turned out to by typos.

Furthermore, when it came to updating the software with additional features, instead of blindly bolting on a new use case we could reduce most of the new feature requests down to library or convenience functions over the core functionality rather than complicating the design with those "new" features.

This latter point is very important in that even though there is pressure to constantly add new features  (and the Pareto Principle applies here), most new features are really just convenience functions that already exist in the software.

I even remember one system where management demanded so many new features (all specified as their own use cases) that the system actually ended up implementing not only the same feature many times but features to disable the requested feature...

Ultimately formal methods is a discipline of thinking, rather than any technique to develop software. Just as much as Agile is a discipline of development.

To use formal methods does not mean any form of top-down or Waterfall development, it does not mean that one has to use refinement or a language like B or Z or VDM or Alloy etc. Just the simple act of writing a precondition to a function in C, or expressing a simple class diagram in UML, or ER diagram to explain a database schema (SQL or NoSQL) to demonstrate the workings of a system, or to clarify what something mean IS being formal.

The best agile developers I have seen all have formal methods backgrounds. The reasoning is that they already have the discipline and education and the tools to think and reason about their system, even if applied implicitly. Agile depends upon great communication between the developers and the customers and giving those customers exactly what they need in a manner that avoids technical debt (viz. situational awareness).

Whether we like it or not, great software engineering comes from understanding how our craft works at its most fundamental levels - imagine civil engineering without the mathematics of physics (a classic example), or even ballet without an understanding of human movement?

References:

[1] Ian Oliver Experiences of Formal Methods in 'Conventional' Software and Systems Design. FACS 2007 Christmas Workshop: Formal Methods in Industry. BCS London, UK, 17 December 2007 

[2]  Ian Oliver Experiences of Formal Methods in 'Conventional' Software and Systems Design





Sunday, 25 August 2013

Fail fast, fail often, fail always

Apparently failing fast and failing often will lead to an eventual success, assuming of course that you are able to give the project or whatever it is time to develop and mature to a sufficient degree so that "failure" can be meaningfully assessed.

Failure does not necessarily mean that the project will not be a success, but rather that the technology, knowledge and product doesn't necessarily satisfy the current business goals. This is quite different from something that is a failure.

The mentality that everything should be an immediate success and that the smallest flaw is evidence of failure is killing not just research and innovation but the whole research and development process.

Furthermore the tendency to rapidly kill projects perceived to be failures without understanding what can be learned from those project and applied to bolster the next or parallel projects will eventually kill your business.

Innovation only comes from allowing scientists and engineers time to develop their ideas and not by rapidly killing those ideas before enough learning can be gained from them to benefit the overall business.

Indeed, if you do want to fail fast and fail often, ensure that you are learning from your mistakes and capitalising on the technologies and knowledge gained so that the fail often doesn't become fail always.

Tuesday, 16 April 2013

Programming Language Frustration

I've been writing a lot of Opa recently - for those of you who don't know, Opa is a framework for writing web software without the hassle of worrying about database connections, distribution of code between front and back-end systems, asynchronous vs synchronous calls etc. It also cleverly integrates code, HTML and CSS holistically into the language. It is basically a mix of cool functional programming ideas with Javascript and a compiler that generates Javascript to run on Node.js; along with MongoDB (and soon Postgres) integration.

What Opa is brilliant at is abstracting away from all the awkward stuff that web (and thus distributed and network) programming. To make life simpler and programs more robust it is also strongly typed but does support polymorphism, variant (or sum) records etc. It can be a bit of a pain when settling down on your data schemata BUT you should be thinking hard about this stuff anyway. For you agile people go read about technical debt, for the privacy people who also worry about data, go read about the slow data movement.

It has its fair share issues too; some features are missing, eg: monads, but that's curable, but the main problem with Opa, and this is shared amongst many cool things in the software engineering community, and that is documentation.

Opa has a book and basic tutorials, a twitter feed, API documentation and forums (locally and StackExchange), plus you can actually get hold of the guys developing Opa. All very good but the experts on Opa are the people who developed Opa and not the people developing in Opa.

Opa's programming community is very, very small and this seriously holds back the acceptance of use of the language.

In Pirsig's book Zen and the Art of Motorcycle Maintenance, Pirsig talks about the quality of components - specifically how threading the head of a screw can render the greatest motorbike useless. The quality of the whole is dependent upon even the smallest, singular part.

And so it is sometimes with Opa: the lack of a specific example, a relevant explanation for a particular function in a library, how to compose specific kinds of database query etc, can bring a project to a screeching halt with no way forward. Getting past this is critical to any larger scale acceptance and use of the framework/language.

For Opa to succeed it needs better integration between the Opa developers and the developers of Opa. It needs a constant stream of questions, bad code, good code, homemade tutorials etc to develop that external body of knowledge, a set of patterns, case studies from industrial environments, cool solutions to common problems, etc.

I'm constantly amazed at how quickly I can get things done with Opa (apart from CSS which really is the language of evil and frustration) and would recommend it to anyone who needs to develop quick web applications. But to those who do use it, please give something back to the community in expressing what went right and what went wrong, patterns for common problems (eg: OAuth, social network integration, database usage etc)

OK, enough venting of frustration...back to honest coding now...pity that so little time is spent with Opa, most of it seems to be fiddling with the user interface (html and css)...sigh :-)

Links


Thursday, 28 March 2013

More Maxims for Privacy

I wrote some maxims for privacy a while back, but still I'm looking for that crystalisation of privacy - the "one slider" or "one sentence" that encompasses the foundations, or the basics of privacy.

For the most part privacy comes down to data collection and subsequent usage of that data - the rest is just additions to that. At least if we're concentrating on privacy and not the wider scheme of information management of which I believe privacy is just a sub-speciality, albeit a rather important one.

So, when dealing with information:

"If you don't have a use for it, 
don't collect it!"

For me this sums it up. It links data collection and usage in a way that clearly states that just collect what you need right now; don't even think about the future uses yet. Interestingly I also think that deliberately restricting the data collection right at the start to what you absolutely know you are going to use immediately forces you (the software/system developer) to better focus on the product at hand - "Slow Data" anyone?

In these agile development days however, it is often argued that we'll develop the usages later and collect everything now. How often does this really happen? And, if you really were agile then you'd construct your system initially to do the minimum it needs to and get that out to the customer for their appraisal. If that goes well (or not), then modify as necessary during later stages in your agile development process.

If you're not agile (which apparently is waterfall, though I'm not sure), then you should have worked out what you need and work from there; which again should be self-limiting on the data collection. Surely in a good, fully worked out design you wouldn't be collecting superfluous things?

So, that's it, the essence of privacy as a single sentence; the rest is just layers pertaining to things such as provenance, data retention, purpose, infrastructure etc - that's what makes good information management a whole discipline in itself, of which privacy is one small, but important part.

Wednesday, 23 January 2013

Kubler-Ross and Getting Ideas Accepted

When discussing new or challenging ideas, or even anything that challenges or even questions the existing schools of thought (or business process!) there is often much "push-back" with responses such as "that'll never work", "impossible" etc...sometimes even when confronted with the evidence and demonstration.

Dealing with this is often soul destroying from the innovator's perspective and getting past this is 90% of the challenge of getting new ideas and view points accepted. So having a mechanism to understand the responses would be useful. I think the Kubler-Ross model might be useful here to examine people's responses.

The model itself was developed for psychologists to understand the process of grief. While the model has sparked some controversy, this does not detract from the basic principle of the model. The model consists of five sequential stages:
  1. Denial - "we're fine", "everything works"
  2. Anger - "NO!"
  3. Bargaining - "Ok, so how do you fix this?"
  4. Depression - "Why bother...?", "Too difficult"
  5. Acceptance - "Let's do this!!!"
When applied to challenging ideas, the person rejecting those ideas has to proceed through the above stages - and the challenger has to also acknowledge this and work within this.

Let's say we have a process and metrics for some purpose - the process is complicated and dogmatic, the metrics measure some completion rate but not effort or compliance. A challenge to this might be met with the following responses:
  1. Denial - the process works! No-one has complained! We have metrics! We're CMM Level 3!
  2. Anger - Why are you complaining? We don't need to change!
  3. Bargaining - OK, we'll consider your ideas and changes but we're not promising anything. Can you come up with a project plan, budget, strategy, PowerPoints etc...?
  4. Depression - OK, there are problems, but we can't deal with them. It's too late and complex to change. Let's create a project plan, strategy and vision. How can we ever capture those metrics?
  5. Acceptance - You're right, let's run with this
Actually the last state - acceptance - probably works very well in a more agile environment, but agility requires both a deep and holistic and ultimately an approach grounded in the theory of the subject at hand. Do not underestimate getting management support either, and conversely as a manger giving real support is similarly critical.

This model must be used in an introspective and reflective manner to ensure that you as the originator and presenter of the idea do not fall into the trap of stages 1 and 2 yourself. Understanding your reactions in the above terms is very enlightening regarding your own behaviour.

If you do reach stage 3 in the discussions then this is time that you need to be absolutely sure in how your idea works, what the flaws are and how it integrates and improves what came previously. At this stage you have the chance to get everyone on board but after this however it is extremely difficult to turn people to your idea.

Stage 4 is depression all round, you will probably have accepted many changes to your idea and let go of some cherished ideas. Worse is that you've probably challenged the existing school and dogma to such a degree you are going to get a lot of "push back" on the ideas. In some respects this is where ideas do die either "naturally" or through "suicide" to use some dark terminology. To get through this stage you need to be the supporter of everyone. Indeed emphasis on the previous school of thought as being the catalyst to the newer ideas is critical to get through this; after all, wasn't it the previous systems that sparked the need for change in the first place?

Stage 5 is requires real leadership of the innovation and building of the team to carry this forward. Like it not, teamwork and ensuring that everyone, even the detractors, have a voice is critical. Sometimes your challenge might free some of the original detractors out of their earlier beliefs - this can come as quite a relief to these people and offer them badly needed, new challenges and purpose.

There are many more things one could write on this and there are many books and theories on how to manage innovation and invention elsewhere. The idea here was to relate some experiences with the Kubler-Ross model and understand things in that context, which personally I've found to be a very useful tool.

Tuesday, 18 December 2012

Code is Law, Inherent Privacy and a Few Uncomfortable Issues

Lawrence Lessig stated that "code is law" - a maxim that above all should be the most critical in software engineering, especially when put in the context of implementing privacy and security.

I want to talk about some issues that worry me slightly (ok, a lot!). The first is that despite of policies, laws etc, the final implementation of anything related with privacy is in the code the programmers write. The second is that we are building our compliance programmes upon grand schemes and policies and paying piecemeal attention to the actual act of software engineering. The latter we attempt to wrap up in processes and "big ideas", for example, Privacy by Design.

Now before the PbD people get too upset, there's nothing wrong with stating and enumerating your principles, the Agile Manifesto is a great example of this, however there is no doubt that many implementation of agile are poor at best and grossly negligent and destructive at worst. The term used is "technical debt".

Aside: the best people I've seen conduct software development in an agile manner are formal methods people...I guess due to the discipline and training in the fundamentals they've received. This also applied to experienced architects, engineers and programmers for whom much of this formality is second nature.

Addressing the first point: no matter how many policies or great consumer advocates or promises you make, at the end of the day, privacy must be engineered into the architecture, design and code of your systems. It does not matter many powerpoint slides or policy documents or webpages your write, unless the programmers "get it", you can forget privacy, period!

Aside: Banning powerpoint may not be such a bad idea....

Herein lies a problem, the very nature of privacy in your systems means that it crosscuts every aspects of your design and ultimately your whole information strategy. Most of these things do not obviously manifest themselves in the design and code of your systems.

To solve this there must be a fundamental shift from the consumer advocacy-legal focus of privacy to a much deeper, technical or engineering, even scientific approach. This however does not just mean focusing on the design and code, though that is fundamental to the implementation, but to the whole stack of management and strategy from the highest directors to the programmers.

I've seen efforts in this direction but stop at the product management - "Hey, here are the privacy requirements - implement them!" ... which does feel good in that you are interacting, or believe that you are interacting, with the products you are producing but still not sufficiently with the people who really build these. Just producing requirements doesn't help: you need that interaction and communication right across the company.

Of course all of the above is extremely difficult and leads us to our next point which is how we build our compliance programmes in the first place. The simple question here is "are you fully inclusive?", meaning do you include programmers, architects (technical people with everyday experience) or is the programme run by non-technical, or formerly technical staff? Invariably it is the latter.

Compliance programmes must be inclusive otherwise the necessary inherency required to successfully and sufficiently implement the ideas and strategies of that programme will be lost - usually in a sea of powerpoint and policy documents.

Firstly in order to achieve inherent privacy (or security, or xyz) focus must lie on onboarding and educating the programmers, the designers and the architects and less focus on the management, prescription and consumer advocacy. Secondly, any compliance programme must be inclusive and understand the needs of the said technical staff. Thirdly, the engineering and technical staff are the most critical components in your organisation.

Compliance programmes are often measured on the amount of documentation produced (number of slides even?), however this ends up with a self feeding process where for the compliance programme to survive it needs to keep the fear of non-compliance at the fore. Read Jeff Jarvis' article on Privacy Inc.: Scare and Sell and then Jim Adler's talk about PII2012 on The Emergent Privacy-Industrial Complex and you get an idea of what is going wrong. Avoid at all costs creating a privacy priesthood in your compliance programmes.

Aside: This might be good old fashioned economics - if a compliance programme actually worked then there'd be no need for the programme in the end.

There are two interrelated caveats that also need to be discussed, the first of which is that any work in privacy will expose the flaws, holes and crosscutting issues across your products, development programmes and management and engineering skill bases. For example, a request to change a well crafted design to cope with some misunderstood ambiguity in privacy policy is going to end in tears for all concerned. It will demand of management, engineering and your compliance programme a much deeper [scientific] knowledge of what information your products are using, carrying, collecting and processing - to a degree uncommonly found in current practices.

The fundamental knowledge require to really appreciate information management and privacy is extensive and complex. Awareness courses are a start but I've seen precious few courses even attempting to cover the subject of privacy from a technical perspective.

Secondly, privacy will force you to examine your information strategy - or even create and information strategy - and ask very awkward and uncomfortable questions about your products and goals.




Thursday, 22 November 2012

Information Privacy: Art or Science?

I was handed a powerpoint deck today containing notes for a training course on privacy. One thing that struck me was the statement on one of the slides, in fact it was the only statement on that slide:

PRIVACY IS AN ART

This troubles me greatly and the interpretation of this probably goes a long way into explaining some things about the way information privacy is perceived and implemented.

What do we mean by art, and does this mean that privacy is not a science?

Hypothesis 1: Privacy is an art

If you've ever read great code it is artistic in nature. You can appreciate the amount of understanding and knowledge that has gone into writing that code. Not just at the act of writing, or the layout and indentation, but in the design of the algorithms, the separation of concerns, the holistic bigger picture of the architecture. Great code requires less debugging, performs well, stays in scope, and if it ever does require modification, it is easy to do. Great programmers are scientists - they understand the value to the code, they avoid technical debt, they understand the theory (maybe only implicitly) and the science and discipline behind their work and in that respect they are the true artists of their trade.

For example, Microsoft spent a lot of effort in improving the quality of its code with efforts such as those the still excellent book Code Complete by Steve McConnell. This book taught programmers great techniques to improve the quality of their code. McConnell obviously knew what works and what didn't from a highly technical perspective based on a sound, scientific understanding of how code works, how code is written, how design is made and so on.

I don't think information privacy is an art in the above sense.

Hypothesis 2: Privacy is an "art".

In the sense that you're doing privacy well in much the same was as a visitor to an art gallery knows "great art". Everyone has their own interpretation and religious wars spring forth over whether something is art or not.

Indeed here is the problem, and in this respect I do agree that privacy is art. Art can be anything from the formal underpinnings of ballet to the drunken swagger of a Friday night reveler - who is to say that the latter is not art? Compare ballet with forms of modern and contemporary dance: ballet is almost universally considered "art" while some forms of contemporary dance is not - see our drunken reveler at the local disco...this is dance, but is it art?

Indeed sometimes the way we practice privacy is very much like the drunken reveler but telling everyone at the same time that "this is art!"

What elevates ballet, or the great coder, to become art is that they both have formal, scientific underpinnings. Indeed I believe that great software engineering and ballet have many similarities and here we can also see the difference between a professional dancer and a drunken reveler on the dance floor: one has formal training in the principles and science of movement, one does not.

Indeed if we look at the sister to privacy: security, we can be very sure that we do not want to practice security of our information systems in an unstructured, informal, unscientific manner. We want purveyors of the art - artists - of security to look after our systems: those that know and intuitively feel what security is.

There are many efforts to better underpin information privacy, rarely do these come through in the software engineering process in any meaningful manner unless explicitly required or audited for. Even then we are far from a formal, methodical process by which privacy becomes an inherent property of the systems we are building. When we achieve this as a matter of the daily course of our work then, and only then, privacy will become an art practiced by artists.

Tuesday, 28 August 2012

Opa Tutorial - Intermission

Cedric Soulas of MLState - the creators of Opa - has very kindly put up some suggestions on writing code based on my tutorials. They're available via GitHub at https://github.com/cedricss/ian-oliver-tutorials . My code resides over on SourceForge.

While these are based on part 4 of the series they are applicable to later parts and indeed I will integrate these in due course.

One thing I do want to point out now is the use of a parser instead of an explicit pattern match dispatching URLs to specific functions. Very briefly the code which reads:

function start(url)
{
  match (url)
   {
       case {path: [] ... }: hello();
       case {path: ["expressions" ] ... } : expressionsRESTendpoint();
       case {path: ["expressions" | [ key | _ ] ] ...} : expressionWithKeyRESTendpoint(key);
       case {~path ...}: error();
   }
}

Server.start(
   Server.http,
     [ {resources: @static_include_directory("resources")} , {dispatch: start} ]
);


can be rewritten using a parser:

start = parser {
   case "/": hello();
   case "/expressions" : expressionsRESTendpoint();
    case "/expressions/" key=((!"/".)*) (.*):      expressionWithKeyRESTendpoint(Text.to_string(key));
   default: error();
}

Server.start(

   Server.http,
   [ {resources: @static_include_directory("resources")} , {custom: start} ]
);


Which performs more or less the same function with the bonus that we obtain much more flexibility in how we process the URL - rather than treating it statically in the pattern matching. Note how we're no longer calling an explicit function but now have a parser as first-class object :-)


At this time there's relatively little documentation on the parser in Opa, but on the Opa Blog there's a tantalizing glimpse of what is possible.


So with that to whet your appetites go and download the latest nightly build and start coding...while I finalise composing part 5...

Sunday, 19 August 2012

Opa Language Tutorial: Part 4

Following on from part 3, we now quickly finish everything by handling all the GET, POST, PUT and DELETE verbs for our two cases:

Verb /expressions /expressions/"k"
GET return a list of expression identifiers even if empty. Return a 200 success code return the full details of expression "k". If "k" doesn't exist then return a 404 error
POST add the requested object if the supplied key in the object doesn't exist. Return a 201 success code as well as the key "k", otherwise return a 400 error. not allowed, return a 400 error
PUT not allowed, return a 400 error modify the database with the given object if the supplied key both exists in the database and matches the key in the supplied object - return a 200 success code. In all other circumstances return a 400 error.
DELETE not allowed, return a 400 error delete the database entry with the given key if it exists in the database and return a 200 success code. In all other circumstances return a 400 error.

Let's go through each of the cases above in turn with minimal discussion of the code. I'm also going to tidy up the code a little, correcting the HTTP responses, making sure we're calling the correct messageSuccess and messageError functions accordingly.

For the case where we deal with urls of the form http://xxx/expressions, ie: without any key we make the matching in the second case statement in the start function:

function start(url){
  match (url)   {
       case {path: [] ... }: hello();
       case {path: ["expressions" ] ... } : expressionsRESTendpoint();
       case {path: ["expressions" | [ key | _ ] ] ...} : expressionWithKeyRESTendpoint(key);
       case {~path ...}: error();
   }
}

which detects URLs without a key associated and passes these off to the expressionsRESTendpoint function:

function expressionsRESTendpoint(){
   match(HttpRequest.get_method())   {
      case{some: method}:
         match(method)         {
             case{get}:
                expressionsGet();
             case{post}:
                expressionsPost();
             case{put}:
                messageError("PUT method not allowed without a key",{bad_request});
             case{delete}:
                messageError("DELETE method not allowed without a key",{bad_request});
             default:
                messageError("Given REST Method not allowed with expressions",{bad_request});                  }
      default:
          messageError("Error in the HTTP request",{bad_request});
   }
}


which matches the GET and POST verbs, and then anything else with an HTTP 400 Bad Request, plus a natural language error message.

Because network programming suffers from the leaky abstraction problem we also need to catch the cases where we fail to get a method, in this case the default: of the outer match block handles this.

The functions expressionsPost and expressionsGet are as described earlier in part 3.

The case where a key is supplied with the URL, this is handled by the 3rd case statement in the start function and control is passed to the expressionWithKeyRESTendpoint function , which operates in the same way as the "without key" case:

function expressionWithKeyRESTendpoint(key){
   match(HttpRequest.get_method())   {
      case{some: method}:
         match(method)         {
             case{get}:
                expressionGetWithKey(key);
             case{post}:
                messageError("POST method not allowed with a key",{bad_request});
             case{put}:
                expressionPutWithKey(key);
             case{delete}:
                expressionDeleteWithKey(key);
             default:
                messageError("Given REST Method not allowed with expressions with keys",{bad_request});
         }
      default:
          messageError("Error in the HTTP request",{bad_request});
   }
}


The procedure to GET is relatively straight forward in that we check that a record with the given key exists and match the result accordingly:

function expressionGetWithKey(key){
    match(?/regexDB/expressions[key])    {
       case {none}:
          messageError("No entry for with id {key} exists",{bad_request});
       case {some: r}:
          Resource.raw_response(
             OpaSerialize.serialize(r),
             "application/json",
             {success}
          );
    }
}


Deletion is also relatively straightforward:

function expressionDeleteWithKey(key){
    match(?/regexDB/expressions[key])    {
       case {none}:
          messageError("No entry for with id {key} exists",{bad_request});
       case {some: r}:
          Db.remove(@/regexDB/expressions[key]);
          messageSuccess("{key} removed",{success});
    }
}


The expression: ?/regexDB/expressions[key]

is used to check existence, returning an option type which we handle

To remove a record from a database we use the function Db.remove which takes the record as a parameter. Note the use of the @ operator which returns the a reference path to record in the database. Opa's database functions are fairly comprehensive and are better explained in Opa's own documentation - specifically in this case section 14.7.

Now we get to the PUT case; to understand this properly we need to break this down:
  1. First we check if the request contains a body.
  2. If successful, we check that the supplied key exists
  3. If successful, we deserialise the body, which should be JSON
  4. If successful, we convert this to an Opa record and match it to the type regexExpression.
  5. If the key supplied in this object (exprID field) matches the key used in the URL then we simply replace the record in the database in the same manner as we make with our earlier POST function.
Otherwise, there is nothing really special about this particular function, though we do use an if...else structure for the first time and this should be familiar already.

function expressionPutWithKey(key){
 match(HttpRequest.get_body()) {
  case {some: body}:
    match(?/regexDB/expressions[key]) {
       case {none}:
          messageError("No entry for with id {key} exists",{success});
       case {some: k}:
           match(Json.deserialize(body)) {
                case{some: jsonobject}:
                    match(OpaSerialize.Json.unserialize_unsorted(jsonobject))
                      case{some: regexExpression e}:
                         if (e.exprID == key)  {
                            /regexDB/expressions[e.exprID] <- e;
                            messageSuccess("Expression with key {e.exprID} modified",{success});
                         }
                         else  {
                            messageError("Attempt to update failed",{bad_request});
                         }
                      default:
                         messageError("Missing or malformed fields",{bad_request});
                    }
                 default:
                       messageError("No valid JSON in body of PUT",{bad_request});
               }
           }
   default:
      messageError("No body in PUT",{bad_request});
 }


...and with that we conclude the initial development of the application or service (depending on your point of view) and shown basic database interaction, simple processing of URLs, handling of JSON serialisation/deserialisation and handling of the major HTTP methods: GET, POST, PUT and DELETE, plus some simple error handling.

The code up to this point is available on SourceForge and the file you're looking for id tutorial4.opa.

Now for a little discussion...is this the best we can do and why Opa? To answer the second question first, Opa gives us a level of abstraction in that we've not had to worry about many aspects of programming internet based services that many other frameworks have. In a later part we'll talk more about how Opa decides to distribute code between the client and server plus how to use Opa's features for distributing code for scalability and fault-tolerance. So Opa is making a number of architectural decisions for us, in part this is embedded in the nature of Opa - being a compiled language not an interpreted language. Furthermore Opa is strongly typed which means all of our typing errors (well most) are already caught at compile time. This simplifies debugging and forces a more disciplined approach to programming; there is however a caveat (or two) to this last statement.

The code written here is fully functional, written in an agile manner (which may or may not be a good thing) and also written in a rigorous manner (refinement of specification, testing etc). What is wrong with the code is that it is profoundly ugly and that comes from the style of development which in this case has been based around developing a set of individual use cases (eight of them, 2 families of access and 4 verbs).

While use case based development provides us with a good deal of the information we need to know about how our system needs to behave and in what cases, and indeed the individual use cases compose quite nicely - our program works doesn't it? - this does not result in an elegant, maintainable piece of software that performs nor satisfies our needs well. For example, if we need to change how we access the database, or even reuse functionality we end up reintroducing similar code again and often trying to find every instance of code that performs that functionality and modifying that consistently. For example, look how many times we've needed to check whether deserialisation needs to be performed and checked for, or that notice how the patterns for each of the two major use case families (with keys and without keys) are broadly similar but we have repeated code.

What we're left with here is building to be a massive amount of technical debt - once we've added code to manage sets of expressions this becomes painfully obvious; I'm not going to do that in this series, I want (need!) to rewrite this better now. Read the interviews with Ward Cunningham and Martin Fowler about this and you'll see why the code here isn't that elegant. In the next parts of this series I'll refactor the code, take more advantage of Opa's functional nature and show how architecting our design properly, worrying about separation of concerns produces more maintainable code with much higher levels of reuse.

Sunday, 29 July 2012

Opa Language Tutorial: Part 2

Continuing from part 1, I want to extend my application to actually work with some data. Let's go back to the requirements from earlier and look at how we wish to work with those and map these into the REST idea.

Firstly we require a list of regex expressions, with identifiers and descriptions [1], for example:
  • Expression visa1 describes the card number on Visa cards: ^4[0-9]{12}(?:[0-9]{3})?$
  • Expression master1 describes the card number on Mastercard cards: ^5[1-5][0-9]{14}$
  • Expression diners1 describes the card number on Diners Card cards: ^3(?:0[0-5]|[68][0-9])[0-9]{11}$
So we have a data structure of the form: identifier x regex x description, which in turn can be all represented using strings. Opa allows us to define such data structures as types:

type regexExpression = { string exprID, string regex, string description };

As we're being formal about this, let us also decide that the field exprID should be unique, ie: a primary key for referring to any given expression.

Secondly we want to store these somewhere and conveniently Opa provides us with a database mechanism. These are constructed similarly to types above but use the database keyword and database paths:

database regexDB {
   stringmap(regexExpression) /expressions

The above code defines a database called regexDB which contains a "stringmap" structure of regexExpressions and identified using the database path /expressions.

Firstly the fully qualified database path is /regexDB/expressions . Each path can be considered to be a field in the database. Some "fields" we would rather act more like tables and so we use the Opa type stringmap which is equivalent to a dictionary or hashtable in other languages. Stringmap defines the keys to be of type string and we define the value for those keys to be - in this case - regexExpressions.

Part of the REST idea was based upon the CRUD concept and indeed all well behaved databases should follow the CRUD concepts. Fortunately REST and CRUD do map quite nicely together and we can define the operations upon the database and data type we have defined:

First we have to note that the /expressions database path can either be used as is, that is there is a resource, eg: http://a.b.c.d/expressions that we can navigate to, or, because we're introduced the concept of a key through the stringmap we could refer directly to resources contained in or under, eg: http://a.b.c.d/expressions/visa1. This gives us the following table:

Verb /expressions /expressions/"k"
GET return a list of expression identifiers even if empty. Return a 200 success code return the full details of expression "k". If "k" doesn't exist then return a 404 error
POST add the requested object if the supplied key in the object doesn't exist. Return a 201 success code as well as the key "k", otherwise return a 400 error. not allowed, return a 400 error
PUT not allowed, return a 400 error modify the database with the given object if the supplied key both exists in the database and matches the key in the supplied object - return a 200 success code. In all other circumstances return a 400 error.
DELETE not allowed, return a 400 error delete the database entry with the given key if it exists in the database and return a 200 success code. In all other circumstances return a 400 error.

Let us look at the above as a check that they are a) consistent/correct and b) satisfy the various REST principles or invariants. For the GET operation the key must exist otherwise error, similarly for PUT and DELETE. For POST the key must not exist initially. In terms of REST each GET is certainly idempotent and POST, PUT and DELETE act according if accessed multiple times - this all sounds good. We should really write a much better formal specification of this, however we can leave that to the reader :-) So that's a lot of specification and now we should move on to the fun bit of programming! We now define a REST endpoint for the above and this is achieved by adding an additional case statement to our dispatcher:

function start(url) {
   match (url) {
       case {path: [] ... }: hello();
       case {path: ["expressions" | restofpath] ...} : expressionsRESTendpoint(restofpath);
       case {~path ...}: error();
   }
}

and also write some skeleton code for our new expressionsRESTendpoint() function:

function expressionsRESTendpoint(path) {
   Debug.warning("Path is {path}.");
   match(HttpRequest.get_method()){
      case{some: method}:
          Debug.warning("Method is {method}.");
          Resource.raw_status({success});
      default:
          Resource.raw_status({bad_request});
   }
}

The match statement in the start() function should be reasonably self-explanatory in that we call expressionsRESTendpoint() when we match the path of the URI such that the first entry is the "expressions". Note this is a list comprehension so that the variable "restofpath" now refers to the remainder of the list.

The skeleton code for expressionsRESTendpoint() takes a list as its parameter. The first line of this function is a debugging statement - this is Opa's way of debugging by printf: Debug.warning("xyz"). At run-time these statements are output by generated executable to the terminal (stderr?). This statement also shows a feature of Opa which is that you can enter a code block inside a string (or xhtml as we shall see later) - the use of { and } braces denotes the code block. Remember Opa is functional so that a code block will return a value, in this case it is the list in the path variable. Opa also makes the type conversion to string implicitly.

In this function we have a match statement which takes the current context of the HttpRequest to the server and extracts the HTTP method from it. This function call returns an "option"-type in Opa parlance so we need to check whether it actually does have a value or not. For Haskell programmers the equivalent is Maybe. They way we do this is to construct yet another match statement (pattern matching is your friend) and choose between whether the value exists or not. Opa uses the keyword some to find out whether this value exists or not, an in the above, assigns the value to the variable named "method".

Aside: I really need to write a proper tutorial for how match-case and pattern matching works.

Opa's match-case statements also can have a default case to catch cases where nothing is matched. A good tip is always to include a default statement, even if you think you've managed to catch 100% of cases; defensive programming!

Again we include a debugging statement to return the name of the http method. After this we generate a Resource object but this time just built so that it is just effectively an http return code - in this case HTTP1.1 200 OK or success. The default case is similar except that we return the 400 Bad Request error.

Now we can test the above code - after compiling it. To test we use curl as a way of easily inspecting the return codes and controlling what we send. If we issue the following commands:

ian@U11-VirtualBox:~/opatutorial$ curl -X GET http://127.0.0.1:8080/expressions
ian@U11-VirtualBox:~/opatutorial$ curl -X PUT http://127.0.0.1:8080/expressions/ford
ian@U11-VirtualBox:~/opatutorial$ curl -X PUT http://127.0.0.1:8080/expressions/ford/prefect


then on the terminal running our JavaScript executable (remember to compile and run!) then we'll see the output:

[Opa] Server dispatch Decoded URL to /expressions
[Opa] Debug Path is [].
[Opa] Debug Method is {get = {}}.
[Opa] Server dispatch Decoded URL to /expressions/ford
[Opa] Debug Path is [ford].
[Opa] Debug Method is {put = {}}.
[Opa] Server dispatch Decoded URL to /expressions/ford/prefect

[Opa] Debug Path is [ford,prefect].
[Opa] Debug Method is {put = {}}.         

Each group of 3 lines corresponding to the individual curl commands issued. Opa reports the dispatch anyway, the rest is from our Debug.warning commands. Note the path provided and the Path output by the debugging command as a list from the "restofpath" variable set during the match-case pattern matching.

Ok, so what we have is out REST end-point working and tested. Let's finish this off with updating the skeleton code we've written to match the http methods and write code to input the data sent to our database; for the moment we'll just implement POST and get the database running and populated.

function expressionsRESTendpoint(path) {
   Debug.warning("Path is {path}.");
   match(HttpRequest.get_method()) {     
      case{some: method}:
         match(method) {
             case{get}:
                Debug.warning("GET method called");
                Resource.raw_status({success});
             case{post}:
                expressionsPost();    
             default:
                Debug.warning("Some other method called {method}");
                Resource.raw_status({method_not_allowed});           
         }
      default:
          Resource.raw_status({bad_request});
   }        
}



and add a method to handle the post: expressionsPost(). The path isn't interesting for the post so we don't pass it. Out new function however takes the form:

function expressionsPost() {
   Debug.warning("Body is {HttpRequest.get_body()}");
    match(Json.deserialize(HttpRequest.get_body() ? "")) {
       case{some: jsonobject}:
          match(OpaSerialize.Json.unserialize_unsorted(jsonobject)) {
             case{some: regexExpression e}:
                Debug.warning("got object with fields {e.exprID}, {e.regex}, {e.description }");
//                /regexDB/expressions[e.exprID] <- e;
                Debug.warning("record loaded into database...try a get now");
                Resource.raw_status({success});
             default:
                Debug.warning("missing fields in JSON");
                Resource.raw_status({method_not_allowed});
          }
       default:
          Debug.warning("something failed");
          Resource.raw_status({bad_request});
    }
}




Now before anyone asks, yes the above does not conform to my spec (part 3 anyone?) and its full of debug stuff and a commented line referring to the database. The Debug.warning statements you can guess. The get_body() method returns the body of the call to the server similarly to get_method() used earlier.

I will now make an implementation choice: all our REST calls take their parameters as a JSON object in the body of the message. This will make the next line mroe understandable.

HttpRequest.get_body() ? ""

The ? operator is a short-cut for dealing with option types (explained earlier). If in this case a body does exist then return that, else return an empty string. The result of this is passed to the function Json.deserialize will turns whatever string is in the HttpRequest body into JSON. The following case statement:

case{some: jsonobject}



pattern matches that if we have a some JSON object then return this in the variable jsonobject, if not then this is caught by the default: clause later.

We perform a similar trick in the next match statement as shown in this code snippet:

match(OpaSerialize.Json.unserialize_unsorted(jsonobject)) {
  case{some: regexExpression e}:
    Debug.warning("got object with fields {e.exprID}, {e.regex}, {e.description }");
     ...

where

OpaSerialise.Json.unserialize_unsorted(jsonobject)

turns our valid JSON into hopefully valid Opa...if successful then we get some Opa which we coerce (type cast) into our type regexExpression and return it in variable "e". The Debug.warning statement should be self-explanatory.

Aside: yes, this could have been written neater and there might be a better way of dealing with unserialising JSON...I'd certainly like to know the latter.

If we run the above code, say with the two requests:

ian@U11-VirtualBox:~/opatutorial$ curl -X POST -d "hello" http://127.0.0.1:8080/expressions
ian@U11-VirtualBox:~/opatutorial$ curl -X POST -T "regex1" http://127.0.0.1:8080/expressions


NB: regex1 is a file containing some JSON:

{
 "exprID":"abc",
 "regex":"[abc]+",
 "description":"ABC sequence finder"
}


we see the following on the terminal:

[Opa] Server dispatch Decoded URL to /expressions
[Opa] Debug Path is [].
[Opa] Debug Body is {some = hello}
[Opa] Debug something failed
[Opa] Server dispatch Decoded URL to /expressions
[Opa] Debug Path is [].
[Opa] Debug Body is {some = {
 "exprID":"abc",
 "regex":"[abc]+",
 "description":"ABC sequence finder"
}

}
[Opa] Debug got object with fields abc, [abc]+, ABC sequence finder
[Opa] Debug record loaded into database...try a get now


Of course nothing got written into the database (line was commented out), but for the first call we can see that we hit the default match clause for an invalid JSON object. In the second we can see the body and the output of the debug statement that accesses the Opa object directly. So it seems to work.

NB: as I stated earlier, I'm not strictly to my specification here, nor am I being too strict about error handling - this is somewhat deliberate for the moment.

FINALLY, the database: We'll uncomment the line:

/regexDB/expressions[e.exprID] <- e; 

which states that in the expressions part of the regexDB which you recall was a stringmap of regexExpressions, we use the exprID field of "e" as the key and use the whole record as the value associated with this key. Simple addition of a record to a hashtable.

A quick note on deployment: Opa integrates with MongoDB. If you have MongoDB installed and running then fine, if not please refer to their documentation on this. If MongoDB is not installed then Opa downloads it - I'm not 100% clear on what it does but I like to try and keep things neatly managed so I know what is going on so I try to avoid this. I will assume therefore that you have MongoDB running on your local machine. Note the parameter to tell Opa that you wish it to use that instance of the database:

ian@U11-VirtualBox:~/opatutorial$ ./tutorial2.js --db-remote 127.0.0.1:27017
/home/ian /home/ian/.opa
http serving on http://U11-VirtualBox:8080
[Opa] regexDB DbGen/Mongo/SynchroStart Opening database
[Opa] MongoDriver.open 127.0.0.1:27017
[Opa] regexDB DbGen/Mongo/SynchroStart Db is ready
[Opa] regexDB DbGen/Mongo/SynchroStart Process 0 operations on the db wait list, start
[Opa] regexDB DbGen/Mongo/SynchroStart Process 0 operations on the db wait list, finished


So now issue the curl command as earlier

ian@U11-VirtualBox:~/opatutorial$ curl -X POST -T "regex1" http://127.0.0.1:8080/expressions

and I promise, somewhere in MongoDB lies a perfectly formed record. Which of course we can't see because we haven't written any GET statement and in all great academic traditions, this is left as an exercise for the reader.

To summarise:
  • we created a type
  • a database to store records of some type
  • extended the pattern matching to process certain paths differently
  • met option types
  • caught an http method
  • deserialised some JSON into Opa
  • started Opa with an external database (and even maybe installed and run MongoDB along the way)
  • stored a record in that database via a REST call
In the next part I want to clean up the code and make it conform to the specification, write the GET, PUT and DELETE statements, correct the sanity checking and error reporting; and try and validate as much against specification as I can.

Finally, while writing this I was reminded of this quote by Kernighan and Pauger [2]:
 “Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it?”
as I'm writing this tutorial and explaining what I'm doing I'm very quickly finding all those places where my code isn't great, my spec isn't great and more importantly forcing myself to really understanding what is going on...that's the only way you're going to get great code at the end of the day...explain it!

References

[1] Finding or Verifying Credit Card Numbers
[2] B. W. Kernighan and P. J. Plauger, The Elements of Programming Style 2nd Edition, McGraw Hill, New York, 1978. ISBN 0-07-034207-5