ThoughtWorks Studios

ThoughtWorks' Agile Project Management application

ThoughtWorks' Continuous Integration and Release Management application

ThoughtWorks' Collaborative Test Automation application

ThoughtBloggers

Aaron Erickson (feed)
Abdul Salam (feed)
Adam Scott (feed)
Adrian Wible (feed)
Agile Hong Kong (feed)
Akshay Dhavle (feed)
Alex Scordellis (feed)
Alistair Jones (feed)
Amey Shyamchandra Dhoke (feed)
Anand Iyengar (feed)
Anand Vishwanath (feed)
Andrew Keene (feed)
Andy Marks (feed)
Anthony Pitluga (feed)
Avishek Sen Gupta (feed)
Benjie Davis (feed)
Bhavin Javia (feed)
Brandon Hastings Byars (feed)
Brian Guthrie (feed)
Cam Swords (feed)
Carl Ververs (feed)
Carlos Villela (feed)
Chad Wathington (feed)
Chirag Doshi (feed)
Chirdeep Shetty (feed)
Chris Bushell (feed)
Chris Leishman (feed)
Chris O'Meara (feed)
Chris Stevenson (feed)
Christian Blunden (feed)
Cliff Morehead (feed)
Continuous Delivery (feed)
Cruise development team (feed)
Dahlia Bock (feed)
Dan Abel (feed)
Daniel Aragao (feed)
Daniel Wildt (feed)
Danilo Sato (feed)
Darci Dutcher (feed)
Darren Smith (feed)
David Cameron (feed)
David Rice (feed)
David Rupp (feed)
Dean Cornish (feed)
Derek Hammer (feed)
Dinesh Tantri (feed)
Dinesh Tantri (feed)
Duncan Cragg (feed)
Eric Liu (feed)
Erik Doernenburg (feed)
Erik Stepp (feed)
Evan Bottcher (feed)
Fabio Pereira (feed)
Farooq Ali (feed)
Felix Leipold (feed)
Filipe Gomes Esperandio (feed)
Flex Testing (feed)
Francisco Trindade (feed)
Geek Snack (feed)
Gitanjali Venkatraman (feed)
Grant Joung (feed)
Hakan Raberg (feed)
Halvard Skogsrud (feed)
Hao (Vincent) Xu (feed)
Harsha Maiya (feed)
Ian Cartwright (feed)
Ian Robinson (feed)
Isa Goksu (feed)
Jae Lee (feed)
James Barritt (feed)
James Crisp (feed)
James Lewis (feed)
Jason Furnell (feed)
Jason Yip (feed)
Jeff Norris (feed)
Jeff Rogers (feed)
Jenny Wong (feed)
Jez Humble (feed)
Jiangmei kang (feed)
Jie Xia (feed)
Jie Xiong (feed)
Jim Arnold (feed)
Jim Webber (feed)
Jinzhou Chen (feed)
Joe Poon (feed)
John Hume (feed)
John Johnston (feed)
Jonathan Andrew Wolter (feed)
Jonathan McCracken (feed)
Jonny Leroy (feed)
Josh Cronemeyer (feed)
Julio Maia (feed)
Kai Hu (feed)
Kai Ramuenke (feed)
Kailuo Wang (feed)
Ketan Padegaonkar (feed)
Kraig Parkinson (feed)
Kris Kemper (feed)
Kristan Vingrys (feed)
Lachlan Heasman (feed)
Lasse Westh-Nielsen (feed)
Leonardo Borges (feed)
Liang Huang (feed)
Liang Qiao (feed)
Liz Douglass (feed)
Luca Grulla (feed)
Lucas Ward (feed)
Luiz Ribeiro (feed)
Luke Barrett (feed)
Manish Chakravarty (feed)
Manish Kumar (feed)
Marc McNeill (feed)
Marco Valtas (feed)
Mark Burnett (feed)
Mark Needham (feed)
Martin Fowler (feed)
Matthew Dunn (feed)
Matthieu Tanguay-Carel (feed)
Mayur Wadhwa (feed)
Michael Jones (feed)
Michael Long (feed)
Michael Patricios (feed)
Mike Mason (feed)
Ming Jin (feed)
Mo Li (feed)
Neal Ford (feed)
Nicholas Bailey (feed)
Nick Drew (feed)
Nishant Verma (feed)
Nishant Verma (feed)
Nitin Dhall (feed)
Nolan Evans (feed)
Ola Bini (feed)
Patric Fornasier (feed)
Patrick Kua (feed)
Paul Hammant (feed)
Paulo Caroli (feed)
Pedro Pimentel (feed)
Peng Jiang (feed)
Penghong Yang (feed)
Perryn Fowler (feed)
Peter Gillard-Moss (feed)
Philip Calcado (feed)
Prabin Deka (feed)
Pramod Sadalage (feed)
Prasanna N Venkatesan (feed)
Prasanna Pendse (feed)
Preetam Reddy (feed)
Premanand Chandrasekaran (feed)
Pritika Gulliani (feed)
Qihui Qin (feed)
Rafael Ferreira (feed)
Rajveer Singh Rathore (feed)
Ranjan D Sakalley (feed)
Raphael Speyer (feed)
Renee Ovcina (feed)
Reshmi Buthello (feed)
Ritesh M Nayak (feed)
Roger Almeida (feed)
Rohan Kini (feed)
Rohith Rajagopal (feed)
Ross Pettit (feed)
Ruosi Fan (feed)
Ryan Greenhall (feed)
Ryan Greenhall (feed)
Sachin Dharmapurikar (feed)
Sam Newman (feed)
Santosh Sagar Reddy (feed)
Sarah Taraporewalla (feed)
Sean Doran (feed)
Shakir A Shakiel (feed)
Sharlene Mckinnon (feed)
Shaun Jayaraj (feed)
Shaun Jayaraj (feed)
Simon Brunning (feed)
Srihari Srinivasan (feed)
Sriram Narayan (feed)
Sriram Narayanan (feed)
Stephen Chu (feed)
Steve Moyer (feed)
Steven List (feed)
Sudhindra Rao (feed)
Sumeet Moghe (feed)
Suzi Edwards (feed)
Tarek Abdelmaguid (feed)
Thiago Marano (feed)
Thomas Czarniecki (feed)
ThoughtWorkers on Open Source (feed)
ThoughtWorks Studios (feed)
Timothy Camper (feed)
Tomas Varsavsky (feed)
Tuo Huang (feed)
Venkatesh Nannan (feed)
Vivek Prahlad (feed)
Vivek Singh (feed)
Wen Tao (feed)
Wenjing Luo (feed)
William Hegarty (feed)
Ye Zheng (feed)
Yogi Kulkarni (feed)
Yuexin Chu (feed)
Zubair Khan (feed)
__ThoughtBlogs-Admin (feed)

It's really pleasing that finally the book REST in Practice that Savas, Ian, and I have been writing will hit bookshelves on the 24th September. We're pretty pleased that we got it out before the next university term starts (at least in the northern hemisphere), but we didn’t leave a very wide margin. Several university computing departments have already expressed that they're interested in using the book as as recommended text. But we realise we're leaving it late for lecturers to prepare materials.

Fortunately, we have some ready-baked. For a couple of years now Ian and I have been on the conference circuit doing day-long tutorials on the material from the book. Those slides have been all over the Web, and we continue to add and refine them all the time. What's less known is those tutorial slides are actually a subset of much more substantial set that have been used to teach other academics and researchers about the Web, with a distinctly distributed systems flavour.

Here's the good news: if you're an academic who teaches distributed computing and you want to use the full set of slides that we have for your course then you can have the whole set, for free. All we ask in return is that you consider using REST in Practice as one of your recommended texts for your course.

What's more, we'll keep those slides up to date, add more detail over time where it's requested (or we think it's needed), and you'll be able to take that new material as it's created and pushed to our repository.

So if you'd like the full slide set for REST in Practice, first thing to do is drop me an email and we'll sort things out pretty quickly from there.

Nowadays, I tend to use a typed link leading to a form, rather than a heavily typed link alone (I’ll explain what I mean by heavily typed link shortly), to advertise unsafe operations and/or requests that require an entity body. Here’s an example of a typed link:

//Request
GET /shop HTTP/1.1
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Date: Mon, 26 Jul 2010 10:00:00 GMT
Cache-Control: public, max-age=86400
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/rfq"
        href="http://restbucks.com/request-for-quote"
        type="application/vnd.restbucks+xml"/>
</shop>

The link here is typed with the link relation value http://relations.restbucks.com/rfq, which indicates that the link points to a resource where a request for a quote can be submitted. Following the link, the client retrieves a form:

//Request
GET /request-for-quote HTTP/1.1
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Date: Mon, 26 Jul 2010 10:00:05 GMT
Cache-Control: public, max-age=86400
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<model xmlns="http://www.w3.org/2002/xforms"
  schema="http://schemas.restbucks.com/rfq.xsd">
  <submission
    resource="http://restbucks.com/quotes" 
    method="post" 
    mediatype="application/vnd.restbucks+xml"/>
</model>

The response entity body comprises an XForms form model. (Our custom media type definition for application/vnd.restbucks+xml says that one of the things a client can expect to receive in a response is an XForms form model.) The form’s <submission> element includes several pieces of control data: it indicates which verb to use when submitting the form (POST), where to submit the form (http://restbucks.com/quotes), and which content or media type to use when submitting the form (application/vnd.restbucks+xml). Because the definition of our custom media type includes more than one XML schema (much as the Atom specification defines two schemas, one for feeds and one for entries), the form’s control data needs to further clarify what /quotes expects to receive in a POST request. To clarify which schema the POST request body should adhere to, the <model> element’s schema attribute references the rfq.xsd schema.

Here, then, we have all the information a client needs to construct and submit a valid request to the /quotes resource. And all without any fields for the client to fill out.

Heavily typed links

A heavily typed link is one where the link relation describes not only the relationship to the linked resource, but also the HTTP idioms – the control data – necessary to manipulate that resource.

Using a heavily typed link our shop could link directly to the /quotes resource, instead of to a form:

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/quotes"
        href="http://restbucks.com/quotes"
        type="application/vnd.restbucks+xml"/>
</shop>

Here, the definition of the link relation http://relations.restbucks.com/quotes might be something like: “Indicates a collection of quotes. To request a quote, POST a <request-for-quote> with a Content-Type header of application/vnd.restbucks+xml to the linked resource.”

That’s a perfectly respectable way of using links and link relations; in fact, it’s the strategy we employ in REST in Practice. But it can have its downsides. Most importantly, it can increase the coupling between the client and any resources that employ link relations.

Make no mistake: link relation semantics comprise out-of-band knowledge. There’s no magic here: link relations introduce a degree of coupling between a client and any server-governed resources that adopt them. The trick is to keep this coupling as low as possible. By putting control data in the link relation definition, we perhaps introduce more coupling than is strictly necessary.

Out-of-band data is less visible, and more difficult and more costly to change, than data that is inlined in the message. Whilst the control data may not change all that often, changes can and do sometimes happen; inlining the data allows these changes to be propagated to clients sooner rather than later. Control data produced at the time the response is generated is generally more recent than control data defined through some out-of-band mechanism.

Using lightly typed links helps separate semantics from control data. A “light” link relation indicates what the linked resource means in the context of the current representation – that’s all. This helps mitigate against a second, somewhat more subtle, downside of adding control data to link relations: the tendency to introduce action semantics. It’s no great step to shorten the link relation value above to http://relations.restbucks.com/quote, and to rewrite its semantic to read “Indicates an opportunity to request a quote by POSTing a <request-for-quote> with a Content-Type header of application/vnd.restbucks+xml to the linked resource.” At this point, our link has effectively become an operation. The typed-link-to-form strategy helps us concentrate on describing what a linked resource is, rather than what a link does. Link relations do not necessarily imply action semantics, but they can very easily be made to do so.

(Note: when adding links to representations, I still prefer to use a <link rel="..." href="..."> construct, or something similar, rather than <order-form href="...">. The reason for this is that elements such as <link> separate link syntax from semantic context, as explained here; and this is a good thing, because what a link ought look like – its syntax – changes far less than what a link might mean in a particular context. By separating these concerns, we make it easier to evolve a distributed application.)

Interestingly, on the wire, the result of submitting an XForm form looks exactly the same as if we’d simply POSTed a <request-for-quote> directly to /quotes:

//Request
POST /quotes HTTP/1.1
Host: restbucks.com
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<request-for-quote xmlns="http://schemas.restbucks.com/rfq">
  <items>
    <item>
      <description>Costa Rica Tarrazu</description>
      <amount>250g</amount>
    </item>
    <item>
      <description>Guatemala Elephant Beans</description>
      <amount>250g</amount>
    </item>
  </items>
</request-for-quote>

Knowing this, we could always add both a lightly typed link to a form and a heavily typed link to our shop representation:

<shop xmlns="http://schemas.restbucks.com/shop">
  <link rel="http://relations.restbucks.com/rfq"
        href="http://restbucks.com/request-for-quote"
        type="application/vnd.restbucks+xml"/>
  <link rel="http://relations.restbucks.com/quotes"
        href="http://restbucks.com/quotes"
        type="application/vnd.restbucks+xml"/>
</shop>

Two paths to the same result. I don’t recommend doing this: I include simply to highlight how a linked form achieves the exact same result, but with the added beenfit of having inlined control data.

Pre-filled forms/self-describing requests

Here’s another example of using a typed link to a form:

//Request
GET /quotes/1234
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Cache-Control: public
Date: Mon, 26 Jul 2010 10:01:00 GMT
Expires: Mon, 02 Aug 2010 10:01:00 GMT
Content-Type: application/vnd.restbucks+xml
Content-Length: ...

<quote xmlns="http://schemas.restbucks.com/quote">
  <items>
    <item>
      <description>Costa Rica Tarrazu</description>
      <amount>250g</amount>
      <price currency="GBP">4.40</price>
    </item>
    <item>
      <description>Guatemala Elephant Beans</description>
      <amount>250g</amount>
      <price currency="GBP">5.30</price>
    </item>
  </items>
  <link rel="http://relations.restbucks.com/order-form"
        href="http://restbucks.com/order-forms/1234"
        type="application/vnd.restbucks+xml"/>
</quote>

The link relation http://relations.restbucks.com/order-form indicates that the linked resource is something that allows an order to be submitted. Following this link, the client retrieves an order form:

//Request
GET /order-forms/1234
Host: restbucks.com
Accept: application/vnd.restbucks+xml

//Response
HTTP/1.1 200 OK
Cache-Control: public
Date: Mon, 26 Jul 2010 10:01:05 GMT
Expires: Mon, 02 Aug 2010 10:01:00 GMT
Content-Type: application/vnd.restbucks+xml
Content-Length: ...
Content-Location: http://restbucks.com/quotes/1234

<model xmlns="http://www.w3.org/2002/xforms">
  <instance>
    <quote xmlns="http://schemas.restbucks.com/quote">
      <items>
        <item>
          <description>Costa Rica Tarrazu</description>
          <amount>250g</amount>
          <price currency="GBP">4.40</price>
        </item>
        <item>
          <description>Guatemala Elephant Beans</description>
          <amount>250g</amount>
          <price currency="GBP">5.30</price>
        </item>
      </items>
      <link rel="self"
            href="http://restbucks.com/quotes/1234"
            type="application/vnd.restbucks+xml"/>
    </quote>
  </instance>
  <submission
    resource="http://restbucks.com/orders" 
    method="post" 
    mediatype="application/vnd.restbucks+xml"/>
</model>

Once again, I’ve used an XForms form model, but this time I’ve pre-filled it with an <instance> element. Even so, there are no form fields to fill in; all the client needs to do is operate the form according to the inlined control data.

The interesting thing here is that /order-forms/1234 simply returns a different representation of the quote resource identified by /quotes/1234 (the response indicates as much in its Content-Location header). By supplying a forms-based representation of the quote, we inline all the information necessary to submit an order to an order processing engine. The client doesn’t need to compose an entity body; it simply needs to operate the form according to its control data. This results in a self-describing message being sent to /orders.

(In a real-world application I’d likely include a signature in the form body. This signature would guarantee that the client hasn’t tampered with the form contents prior to submitting the form to the order processing engine. The effectiveness of the signature depends on an out-of-band trust relationship having been established between the quoting engine and the order processing engine.)

The result of first following the link to the form, and then submitting the form, is to transition the overall state of the distributed application from Quote Requested to Order Placed, as illustrated in the following diagram:

Application state transition

Every request-response pair transforms application state. Retrieving the form enriches the client’s understanding of the current application state; that is, it opens up new opportunities for interacting with other resources. POSTing the form causes the application state to transition from Quote Requested to Order Placed.

The fact that the overall state of the application has changed is of no consequence to the server resources involved; the application state model is nowhere baked into the server resources. As far as the quote resource is concerned, it has simply been asked to surface a forms-based representation of itself. As far as the orders resource is concerned, it has simply created a new, subordinate order resource. This change in application state is, however, important to the client.

Summary

Understand the tradeoffs between inlining and putting control data in an out-of-band mechanism. Use the right controls for the job; understand the many different hypermedia capabilities at your disposal. The best resource for this is Mike Amundsen’s in-depth study of the hypermedia capabilities of many different kinds of hypermedia control. Recently, Andrew Wahbe started examining the need for machine-to-machine hypermedia, and the differences between controls for machines and controls for humans. Watch his blog for further discussion.

My understanding of hypermedia controls has been heavily influenced by my experience of the human web, where links and forms predominate. But when we talk about forms in a machine-to-machine context, it’s not the form field elements that are of interest, it’s the control data elements. These control data elements help program the client on the fly. The term “form” as it applies in a machine-to-machine context is likely an inappropriate metaphor; nonetheless, it does emphasize the fact that unsafe requests – and requests that have an entity body – require different hypermedia capabilities from simple GETs.

Because in the past I’ve tended to think form fields are redundant in machine-to-machine scenarios, I’ve avoided using forms at all, and have instead overloaded link relations with control data. But link relations are not a “get out of jail free” card. In overloading link relations, we add unnecessary coupling.

Coupling, of course, is not an all-or-nothing affair. There are degrees of coupling. We choose to accept some coupling because of the benefits it brings. But that doesn’t mean we should accept more coupling than is necessary; doing so can only inhibit our ability to evolve a distributed application.

As vezes vejo pessoas falando em empreender, nos riscos, e tudo mais… e pergunto! O que impede você de tentar aplicar algumas horas do seu dia em alguma ideia que você entende que pode dar certo?

Li recentemente o livro Rework da 37Signals, empresa de sucesso no desenvolvimento de softwares que não fazem uma série de coisas. E o fato destes softwares não serem capazes de uma série de coisas é que faz esta empresa tão diferente e com tanto sucesso no mercado.

Eles tem foco, eles tem objetivo e eles tem a certeza de que o produto que eles fazem possui um nicho de usuários. E eles trabalham este nicho.

Você já escolheu o nicho que deseja trabalhar?

Para quem é do mercado de TI, você precisa de no máximo R$50 reais para investir em uma primeira idéia. Isto se você quiser investir em um domínio. De resto, você encontra soluções gratuitas e/ou open source, e nas nuvens para ajudar você em tudo o que precisar!

Precisa de um CRM para cuidar do seu negócio? Highrise!

Precisa de um software para gerenciar seu projeto e acompanhar seus planos? Basecamp ou PivotalTracker podem te ajudar!

Precisa publicar sua aplicação? Google App Engine! Heroku!

E você precisa contratar? Para que? Você já tentou fazer sozinho? E você tem pessoas com a mesma identidade que você? Você tem uma empresa que ouve suas ideias e permite que você crie produtos internamente? Pense nisto também.

Eu sempre falo aos meus alunos: nunca deixem de programar. Nunca deixem de treinar. Um diretor que tive me falou, as empresas precisam de poucas pessoas nas suas diretorias, mas as empresas sempre vão precisar de bons programadores, no melhor estilo pragmatic programmers, desenvolvedores atentos no que é importante no desenvolvimento de software. Falo mais sobre “o que é importante” em outro post.

E é no sentimento de “do it yourself” (DIY) que eu acho que as pessoas precisam investir seu tempo. E pensando no início de uma idéia, meu entendimento fecha com o modelo do Getting Real, ou quase… eu entendo que podemos usar um time de até três pessoas para lançar um produto novo. Você não precisa de mais pessoas que isto para fazer as coisas acontecerem. E olhando 37Signals que citei anteriormente, é o modelo dos três mosqueteiros.

E não é procurando soluções mirabolantes, mas procurando as soluções mais simples possíveis (que por acaso são as mais difíceis). Exemplo, converso com colegas de trabalho sobre alguns produtos a serem lançados, mas nenhum produto pode ter mais que 08 horas de desenvolvimento. Como você alcança isto?

A criação de restrições são interessantes para alcançar estas questões. E são 08 horas conscientes de desenvolvimento, nada de eXtreme Go Horse ou algo do tipo.

Com foco, uma bela metáfora, e muita simplicidade! Simplicidade é a arte de maximizar o trabalho que não fazemos. E é isto que precisamos trabalhar em nós mesmos e com os nossos times. O que eu posso fazer, que é muito simples, e pode me ajudar a colocar a cara no mundo e mostrar minha idéia?

O quanto de tempo preciso investir para garantir um produto possível de ser colocado em produção?

Vou precisar virar noites? Não. Tempo é vida. Cuide dela.

Durma bem. Use 1 hora do seu dia para investir no seu projeto. Use técnicas para gerenciar seu tempo e dar o foco necessário, para que o mínimo de tempo que você tenha seja útil para alguma coisa no seu projeto. Faça coisas mais simples.

Capital de investimento? Será que você precisa? Crie uma restrição! Quem sabe isto ajuda você a lançar uma solução mais rápida?

Trabalhe o mínimo para entregar o máximo. Outra questão interessante é de repente você ler este texto e pensar: mas eu quero criar uma empresa de treinamento. Não posso gastar apenas 1 hora por dia.

Pode sim.

Você pode criar vídeo aulas, iniciar vendendo elas para sites que compram este material. Ou fazer vocês mesmo sua forma de distribuição! Pode virar um parceiro no itunes e vender seus vídeos pela loja da apple. Você pode. Pode usar uma plataforma como e-genial / treinatom. Pode.

Você não precisa de uma sala e um lugar físico para dar treinamento. Não hoje, não agora.

Você pode tentar e atingir um mercado muito maior do que você poderia atingir.

Pense nisto.



Tagged: 37signals, agile, cloud, do it yourself, getting real, pragmatic programmer, startup

It is amazing, you can talk to someone, use words that make perfect sense to both parties and still, they don’t communicate at all. I had this experience last week. The Scrum Teams I have been coaching for some time now were scheduled for a meeting with a manager. It was about certain company standards in the area of reporting. The different Scrum Teams were doing the same thing in slightly different ways, no big differences but enough to be visible. Those differences had a good reason: Different preferences how each team wanted to work. Since the teams are self organizing, there is nothing wrong with this approach and either solution makes perfect sense in their given context.

However, in that meeting the POs and SMs of the two teams were told that having different reports was not acceptable – that they could be confusing; which they weren’t because we had already moved people around – and that the company would mandate a specific tool enabling anyone to work anywhere without having to get any introduction. This might work if all the teams would do the same kind of work, however, in this setting the different teams do a different kind of work using different technologies.

I knew that that specific meeting was scheduled to address that very topic. So, on purpose I did not mention this beforehand to neither of the SMs and POs. I was curious to see how they would react and how they would argue. I wanted to see if I was doing a good job as a coach. It was a textbook show. They simply said: ‘No way! We have delivered working software on time since we started with Scrum, this is how we agreed to work in our Scrum Team and it works great for us. We had people moved around and nobody was confused. Last, there are more pressing issues than how certain reports should look like!’. Of course, the manager was not pleased. He argued that this had to be done in order to align the whole company and lay a foundation for future improvements. The Scrum Teams replied by explaining some principles and practices of Scrum. They also described how it makes sense to keep on working the same way and that they would be open for some changes when both teams would see the need for it – however, right now they do not welcome it.

This went on for the best part of the hour. Sadly at the end we were told that we would have to obey with whatever decision the management would come up with. Our reasoning was not understood – we had failed.

What had happened? Each party was perfectly able to follow and understand each word of the discussion. However, the management side did not extract the same kind of information. We had a semantics disaccord. They understood each single word but did not get the meaning of what we were trying to communicate.

I’ve come to the conclusion that this could be explained with the Dreyfus model of skill acquisition.

  • Expert
  • Proficient
  • Competent
  • Advanced Beginner
  • Novice

The Scrum Teams each had about 6 months of hands-on Scrum experience and discovered first hand what it really means to walk the agile walk. They learned a lot about agile and enhanced their theoretical knowledge with hands-on practical experience. Their limited explicit Scrum knowledge became tacit and abundant. Tacit knowledge is knowledge that is difficult to transfer to another person by means of writing it down or verbalising it. It was exactly this tacit knowledge that was missing on the managers’ side to really understand what we were trying to explain. Same words, total different meaning.

The Scrum Teams have moved up the Dreyfus model and are around the competent or even proficient level, whereas the management is still novice, advanced beginner at best. We had an interfacing problem and did not communicate on the same skill level. The risk with that is that you think you understand, but don't understand without realizing it.

I am convinced that this is one of the main challenges when communicating certain topics. You cannot assume that everyone has the same tacit knowledge and thereby the same skill level then you. You need to find a way to describe matters to a novice as tangible as possible. Not an easy feat but a necessity.

Consider the Dreyfus Model whenever you head to a meeting where you have to do a lot of explaining. If you are too far apart on the Dreyfus model, the others won’t be able to understand even if they think they do!!!

A few days back I watched a pretty awesome video by Nick Shackleton Jones about the Affective Context Model. Nick told a great story about the importance of the affective context - the emotional...



A one stop shop for Sumeet Moghe's thoughts about learning in the modern enterprise.
On behalf of ThoughtWorks.
------

We're happy to announce the third edition of DevCamp Bangalore - DevCamp Bangalore 3 ( http://devcamp.in/index.php/Bangalore ) on Saturday, September 4th, 2010.



The event will be sponsored & hosted by ThoughtWorks ( www.thoughtworks.com ) at their office in Diamond District, Bangalore. ( View map )



Registration

Like any BarCamp, registration is on the wiki and there is no registration fee.



DevCamp is an un-conference by the hackers, for the hackers and of the hackers. It's a species of BarCamp where anything a lover of computers and technology would consider important or entertaining goes. The first DevCamp took place a little over two years ago, and we've always had a lot of fun being a part of this event; we're hoping to keep that trend going with DCB3.



What's in store?

DCB3 is going to be packed with informative presentations, Fishbowl sessions, lightning talks, and much more, so don't miss it!



Interested in doing a session?

Please keep in mind the fact that everyone at DevCamp is a hacker, a pro. Assume a high level of exposure and knowledge on the part of your audience, and tailor your sessions accordingly. Avoid 'Hello World' and how-to sessions which can be easily found on the net. First hand war stories, in-depth analyses of topics, and live demos are best.



Add your abstract/presentation topic here



There are just 3 days left, so don't forget to sign up, and do pass the message along to anyone you think would be interested.



We hope to see you there!


-----

shenheng对《系统复杂之路》评论道:

连自己也维护不了的代码,难道可以靠神一般的咨询师?玩笑开大了吧,咨询师的到来,与葬礼上的神父无异!



咨询师会带来天翻地覆的变化,这样的期许本身就是不现实的。



其实,我也不喜欢咨询师。



做咨询之前,我一直想不通,有什么问题自己搞不定,非要请咨询师。founder_chen说,如果大家都像你一样,咨询就没活干了。



可惜,世界上还有很多咨询师,后来,我也成了一个。



做咨询一段时间,我常困惑于我到底可以给客户带来什么。



于今,我释然了。我只不过关注着一些那些人不曾关注过的东西,比如软件设计,比如Clean Code,比如重构,比如TDD,比如如何做程序员,比如如何做事。而在客户那里,我所做的,只是把这些东西以他们习惯的方式展现给他们。



我只是打开一扇门。



做了个培训,结尾,有人问,怎样才能保证设计的一些东西在后续的开发过程中不被破坏。



好问题,保证不了。



真正保证设计不被破坏的是团队,而不是软件设计本身。团队里需要有人知道代码应该写成什么样子,需要有人清楚系统架构是什么样子,需要有人有正义感,在有人无心伤害时,敢于出来喊一嗓子。

在原有的环境下,这样的人对于其他的工作方式知之甚少。不是他们不努力,很多时候,他们只是不知道自己不知道。我所能带给他们的就是,让他们知道另一片风景的存在。

Entry by Adam Monago

Entry

Software teams, in the broader sense, are complex adaptive systems.  They live within organizations populated by many actors, influenced by the methods, practices and behaviors that coexist with them.  Most of all, they have the capability to learn and adapt to each new entrant into their world.  It is for this reason that, we tend to avoid recommending ‘best practices’ that all software teams can follow for success, let alone ‘agility’.

At ThoughtWorks Studios, we have defined our ideal state as being one of continuous delivery: one in which the customers and users of software have maximum ownership and influence of the development process.

Read the full article at Tech Journal South (http://www.techjournalsouth.com/2010/09/best-practices-for-adaptive-software-teams/)

Keywords

continuous delivery, adaptive software teams, continuous deployment
At TWU, I have heaps of fun doing our little Pecha Kucha Nights and last week was no exception. Now I upload the slide-decks here, but I must say that's never a substitute for a live performance....



A one stop shop for Sumeet Moghe's thoughts about learning in the modern enterprise.
Why testing private methods? Well, it's not really about private vs public, if you want really fine granular unit tests that always only test no more than a couple of lines of code, you will need to do partial mocking and test private methods.



I heard argument that testing private methods exposes too much implementation and thus makes later refactoring harder. My argument is that unit test is part of the implementation. Fine grained "real unit" tests is very easy to read and understand. They help clarify the intent of that couple of lines of code in your target class. If you change implementation code, it should be perfect normal if you also need to change that simple unit test. On the other hand if your tests are in a larger granularity, then in each test, either you test a lot of code or your use a lot of mocking. Either case, chances are whenever you change implementation, you would need to change even more test code.



Another common practice is to extract private methods to another class and make them public and test from there. To me, there are only a few valid reasons to introduce a new class (or in general, to design), being able to test private methods isn't one of them.



Alright, with excuses all said (your argument is welcome), here is how I test private methods in ruby with rspec. I defined a global method in a file called describe_internally.rb in my test folder



def describe_internally *args, &block

example = describe *args, &block

clazz = args[0]

if clazz.is_a? Class

saved_private_instance_methods = clazz.private_instance_methods

example.before do

clazz.class_eval { public *saved_private_instance_methods }

end

example.after do

clazz.class_eval { private *saved_private_instance_methods }

end

end

end





then whenever I need to test private methods for a class (say Foo), I use "describe_internally Foo" instead of "describe Foo". If you prefer, you can organize these two types of tests in the same file as the below example (say Foo is a class with two methods-a public one: "kick" and a private one: "aim" which returns the target to be kicked)



describe Foo do

describe "kick" do

it "should kick at where aim is" do

foo = Foo.new

foo.should_receive(:aim).with(steve_jobs).and_return :a_place

foo.kick steve_jobs

steve_jobs.should be_kicked_at :a_place

end

end

end

describe_internally Foo do

describe "aim" do

it "should aim at where the butt is" do

Foo.new.aim(steve_jobs).should be steve_jobs.butt

end

end

end



If you need an even more fine control of the scope of where you want private methods exposed, Jay Fields wrote a blog long ago giving another approach to achieve it http://blog.jayfields.com/2007/11/ruby-testing-private-methods.html
The team is happy to announce the release of JBehave 3.0. This major milestone has been lead by friend of ThoughtWorks, Mauro Talevi (still no blog) and pushes the usability and nomenclature of JBehave quite a bit.



Read the announcement and release notes.



Summarizing the release notes a little: 7 bugs, 45 improvements, and 11 new features later, JBehave 3.0 is now happily a Git citizen, with repos mirrored from Codehaus to Github.



If thought of as a JUnit plugin (which is an over-simplification) JBehave 3.0 is perfect for "in the box" enterprise development now. Note also there are now plugins for Guice, Spring and PicoContainer to allow Dependency Injection to play a part in the composition of Behavior Driven Development (BDD) tests.

Rs on Rails 2010

On August, 21st of 2010, at RS on Rails 2010, I and Robson Mendonça gave a talk about a game development framework for Ruby called Chingu. Our main goal with this talk was to show that you can have fun with pure Ruby without riding Rails. I believe we successfully achieved that! :D

For those who might have interest, below are our slides (Portuguese only).  Our game’s source code you can find at zukunftsalick’s github.

Ah, one more thing: On September, 12th, I and Carlos Villela will be giving a talk at qCon São Paulo. We’ll be presenting “Especificações de Fora pra Dentro Usando BDD e Selenium 2” roughly translated to “Specifications from outside-in using BDD and Selenium 2″. See you guys there!

Probably Related posts:

  1. RELEASED – “Rails 2.1 – What`s new ?” Book
  2. Open Source Rails
  3. Internacionalizando uma aplicação rails

I've been playing around with Objective C over the last month or so and although my knowledge of the language is still very much limited I thought it'd be interesting to describe some of the things about the language that I think are quite interesting and others that keep catching me out.

Protocols

I touched on protocols a bit in my first post but they seem like an interesting middle ground between interfaces and duck typing.

I like the fact that protocols can define optional methods so that if we're not interested in some parts of the protocol we can just ignore those parts.

From the documentation page:

Protocols free method declarations from dependency on the class hierarchy, so they can be used in ways that classes and categories cannot. Protocols list methods that are (or may be) implemented somewhere, but the identity of the class that implements them is not of interest. What is of interest is whether or not a particular class conforms to the protocol

Smalltalkish style method names

We played with Smalltalk in a coding dojo a bit last year and the first thing that I noticed with Objective C is that the method names are very similar to those in Smalltalk.

I think this influences the way that we define the method name and its parameters as you try and define those in such a way that when you call the method it will read better.

For example I created the following method:

UILabel *aLabel	= [self createLabelFrom:project withXCoordinate:x withYCoordinate:y];

If I didn't have to name the parameters when calling the method I doubt I would have used such descriptive names. I would have just used 'x' and 'y' as the names!

All methods are public/Defining methods in header files

As I understand it all the methods defined on an object are available to any other object to call i.e. all the methods are public

I've read about others using categories to simulate the idea of having non public methods but I haven't tried anything myself yet.

Interestingly we get a compiler warning when trying to call methods on an object if those methods haven't been defined in the appropriate header file although the code still seems to execute fine at run time.

Messages not method calls

One other thing that I sometimes forget is that we're dealing with messages rather than method calls.

We still need to send the message to 'self' even if it's a message being sent to another method on the same object.

Writing in the FT's Long View column, James Mackintosh makes the point that hedge fund managers “appeared smarter than they really were, because they were taking a risk they did not recognize.” That’s an apt description for a lot of what goes on in IT, too.

Despite all of the risks that commonly befall an IT project, we still deal with IT planning as an exercise in deterministic forecasting: if these people do these things in this sequence we will produce this software by this date. The plan is treated as a certainty. It then becomes something to be optimized through execution. As a result, management concerns itself with cost minimization and efficiency of expenditure.

Trouble is, an operations plan isn't a certainty. It's a guess. As Nassim Taleb observed in Errors, Robustness and the Fourth Quadrant:

Forecasting is a serious professional and scientific endeavor with a certain purpose, namely to provide predictions to be used in formulating decisions, and taking actions. The forecast translates into a decision, and, accordingly, the uncertainty attached to the forecast, i.e., the error, needs to be endogenous to the decision itself. This holds particularly true of risk decisions. In other words, the use of the forecast needs to be determined – or modified – based on the estimated accuracy of the forecast. This, in turn creates an interdependency about what we should or should not forecast – as some forecasts can be harmful to decision makers.

In an IT project context, the key phrase is: “This holds particularly true of risk decisions.” We take thousands of decisions over the course of an IT project. Each is a risk decision. Yet more often than not, we fail to recognize the uncertainty present in each decision we make.

This comes back to the notion that operations plans are deterministic. One of the more trite management phrases is “plan your work and work your plan.” No matter how diligently we plan our work in IT, we are constantly under siege while “working our plan”. Developers come and go. Business people come and go. Business needs change. The technology doesn’t work out as planned. The people responsible for the interfaces don’t understand them nearly as well as they believe they do. Other business priorities take people away from the project. Yet we still bake in assumptions about these and many other factors into point projections – as opposed to probabilistic projections – of what we will do, when we will be done and how much it will cost.

Our risk management practices should shed light on this. But risk management in IT is typically limited to maintaining a “risks and issues” log, so it’s never more than an adjunct to our plan.

That most IT projects have only rudimentary risk management is quite surprising given the one-way nature of risks in IT. One-way risks are situations where we have massive exposure in one direction, but only limited exposure in another. Taleb gives the example of trans-Atlantic flight times. It’s possible for an 8 hour flight to arrive 1 or possibly 2 hours early. It can’t arrive 6 hours early. However, it can arrive 6 hours, or 8 hours, a day or even several days late. Clearly, the risks to flight duration are substantially in one direction. IT risks are much the same: we may aggressively manage scope or find some efficiency, but by and large these and many other factors will conspire to delay our projects.

The fact that risk in IT is substantially one-way brings a lot of our management and governance into serious doubt. Having a project plan distinct from the risk log makes the hubristic assumption that we will deliver at time and cost, so we must pay attention to the things that threaten the effort. Given that our risk is substantially one-way, we should make a more humble assumption: odds are that delivery will occur above our forecast time and cost, so what do we need to make sure goes right so that we don't? While such a pessimistic perspective may be in direct contrast to the cheerleading and bravado that all too often pass for "management", it makes risk the core activity of management decision making, not a peripheral activity dealt with as an exception.

In Convexity, Robustness and Model Error in the Fourth Quadrant, Taleb makes the point that one-way risk is best dealt with by robustness – for example, that we build redundancies into how we work. Efficiency, by comparison, makes us more vulnerable to one-way risk by introducing greater fragility into our processes. By way of example, think of the "factory floor" approach to IT, where armies of people are staffed in specialist roles. What happens to the IT "assembly line" when one or more role specialists exit, depriving the line of their situational knowledge? Without redundancy in capability, the entire line is put at risk.

Common sense and statistical analysis both conclude that an optimized system is sensitive to the tiniest of variations. This means that when risks are predominantly one-way – such as in IT projects – it behooves us to err on the side of robustness.

That risk in IT is substantially one-way brings a lot of our management and governance into serious doubt. Having a project plan distinct from the risk log makes the hubristic assumption that we will deliver at time and cost, so we must pay attention to this list of things that could go wrong. Given the one-way risk - and the uncertainty of what those risks are - we should make a more humble assumption: delivery will occur well above our forecast time and cost, so what do we need to make sure goes right? While such a pessimistic outlook may be in direct contrast to the cheerleading and bravado that pass for "management", it makes risk the core activity of management decision making, not a peripheral activity dealt with as an exception.

Robustness is the antithesis of efficiency. Maximum efficiency of execution against a plan calls for the fewest people delivering the most output to a predetermined set of architectural decisions. Building in robustness – for example, redundancy of people so that skills and knowledge aren’t resident in a single person, pursuing multiple technical solutions as a means of mitigating non-functional requirements, etc. – will not come naturally to managers with a singular focus on minimizing cost, especially if, like hedge fund managers James Mackintosh was referring to, they’re blissfully unaware of the risks.

So, what can we do?

First, we have to stop trafficking in the false precision of IT project management. This is no easy task, particularly in a business culture rooted in fixed-budgets and rigid planning cycles, buyers of industrial IT expecting that technology labor is interchangeable, and so forth. We won’t change the landscape all at once, but we can have tremendous influence with current business examples that will be relevant to sponsors and investors of IT projects. If we change the expectations of the people paying for IT projects, we can create the expectation that IT should provide probabilistic projections and take more robust – and therefore one-way risk tolerant – solution paths.

Second, we can introduce risk management that is more sophisticated than what we typically do, yet still easy to understand. If you haven’t read the book, or haven’t read it for a while, pick up Waltzing with Bears by DeMarco and Lister. Their statistical model for risk profiling is a good place to start, quick to work with and easy to understand. Nothing stops us from using it today. Now, the act of using the tool won’t make risk management the central activity of project managers or steering committees, but adding a compelling analysis to the weekly digest of project data will shift the balance in that direction. That, in turn, makes it easier to introduce robustness into IT delivery.

On that subject of robustness, Taleb observed:

Close to 1000 financial institutions have shut down in 2007 and 2008 from the underestimation of outsized market moves, with losses up to 3.6 trillion. Had their managers been aware of the unreliability of the forecasting methods (which were already apparent in the data), they would have requested a different risk profile, with more robustness in risk management …. and smaller dependence on complex derivatives.

Given the success rate of IT projects – still, according to the research organizations, less than 40% - IT project managers should similarly conclude that more robustness in risk management would be appropriate.

Today was about to download multiple files from an authenticated FTP server. The native ftp client of Ubuntu didn't help me as expected. I was trying to log into the FTP server and was constantly getting disconnected when trying to perform some operation. When browsed for some alternative found this ncftp client. This actually worked instantly and was pretty easy in installing.



Install NCFTP:

sudo apt-get install ncftp



Log into FTP server: 

ncftp -u username hostname -p





it will prompt for password enter it. Type '?' in the terminal for the list of commands and there you go :)



Check out the NCFTP client for other platforms.
If you are using the ant script to run the ui tests, that script only detects changes in the java code in the target and test project. The R resource file is somehow not included. If you make any change to the layout which requires some change in the R file (your IDE might be able to help you with that), if you then immediately run a simple "ant run-tests", you might get some weird error. It seems that the new layout file has taken effect while the R file has not. In this case, you need to run a "ant clean compile" in your target project and then "ant clean run-tests" in your ui test project.
Go to your Android Market and search for "Light Meter."

It's an Early Access Preview version with only very basic functions.

Give it a try and send me feedback if you would. I will really appreciate it.

Thanks!
1.0 - add calibration function so that the app can work with ambient sensors from multiple manufactures.

1.1 - add depth of field calculation

1.2 - add hyperfocal distance calculation

1.3 - add a depth of field priority mode.
It says "Aplikacja która w przyszłości może będzie dobra, ale na razie jeszcze dużo jej brakuje."

Google translate told me that it's Polish and in English it means "Application that the future can be good, but for now its still a lot missing."

I guess this user must haven't seen the statement I put in the market: "This is an Early Access Preview version , so very premature yet."



The commenter left a rating of 2 stars which changed the 100% 5-star rating so far (5 ratings before this one)



Lesson learned: you can never go too far to manage user expectations.
The release of 1.0 EAP has been getting great responses. In less than 10 days, it got 866 downloads and 11 ratings with an average of 4.5 stars. So here is the 1.0 release.

Changes

+ calibration so that it can work with different ambient sensors on different phones.

+ be able to remember settings

Two help related features pushed to 1.01

Enjoy.
3 weeks from the first release, Light Meter was downloaded more than 2,400 times.

The development went smooth, I just need time. Currently I am working on adding Manual and Av mode, which is going to be release 1.1. The manual mode could be helpful for the app to work with an incident light meter.
I am very glad to announce that Photography Assistant 1.5 Beta was just released to the Android Market.

Features:

+ Aperture priority, Shutter priority and Manual mode for exposure setting calculation

+ Auto Exposure Value (Light Meter function) using ambient light sensor

+ Hyperfocal distance

+ Depth of Field



It was renamed from Light Meter to Photography Assistant.

Please help test this Beta version.
Test Driven Development provides a very structural way for agile coding. One of the steps in TDD is refactor, and this is when we improve our design, but to what extent can it still be deemed as being agile? To remind myself, I would like to write down the *only* two factors that I think are agile to drive this design step:

1) no duplicated code - if the new code is some sort of duplication of an existing logic, or it is destined to be reused by other developers in the team, I would improve the design to avoid (potential) duplication.

2) no unreadable code - if the new code is hard to read, or it makes the existing file(s) difficult to read (for example, the new code might make it harder to navigate), I would improve the design to achieve readability.



That's it. If I find myself designing due to any factors other than these two, I would feel myself being less agile. It happens a lot, sometimes due to the limitations of the technical platform, sometimes due to the "process", but I would keep reminding myself (and maybe the team) that it's not what I preferred.
摘要: 在如今大部分的组织里面,是否给申请技术职位的人提供工作机会——这个最终决定权属于管理部门。经理们雇人,经理们裁人:一切都天经地义。然而在某些组织里面,这些技术人员能否得到工作机会却是取决于——至少部分取决于——他们将来的同事。这种同事预审的最终结果只有一种:当经理们让技术职员拥有发言权的时候,每一个人——申请人、职员和经理——都会和盘托出自己的想法。  阅读全文



mingj 2010-08-31 21:19 发表评论

I’ve been playing with Django & MySQL for a while but for my next project I wanted to integrate it with a PostgreSQL database. Everything went well until I wanted to install Psycopg as my python adapter to PostgreSQL.

After a bit of blundering about here’s what it eventually took:

  • Download and install PostgreSQL one-click installer from http://www.postgresql.org/download/macosx. Remember to read the README file before actually running the installer.
  • Download the psycopg2 source from http://initd.org/pub/software/psycopg/.
  • Edit the setup.cfg file to provide a path to the pg_config executable. On my Mac it sits in /Library/PostgreSQL/8.4/bin/pg_config and is not by default on the PATH so if you don’t put it on the PATH or in this configuration file the next step will fail in a spectacular manner.
  • Run ‘sudo easy_install .‘ in the top level psycopg2 source directory.
  • Specify postgresql_psycopg2 when you configure Django’s database layer for your project.

The cemeteries are full of people who thought they were indispensable.

If you didn’t turn up to work tomorrow, if you never came back, what would happen? I mean, what would really happen?

The world wouldn’t stop.

Can you hand on heart say it would be the end of your organisation? So you may be the ‘key man dependency’, but is that your ego making you think that? (OK, so I once worked with an organisation who had one of those. Their system was written in some obscure language that only one person knew its inner workings. He spent his weekends base jumping. Our job was to migrate the data to a new system to alleviate this risk).

When was the last time you took a holiday? Been too frightened to because you fear everything will fall to peices when you’ve gone? Get over it. Take a vacation, Nothing will change whilst you are away. You’ll get back and nothing will have changed.

What is indispensable?

OK. Now think bigger. History is full of organisations who thought their products and processes were indispensable. Of the FT30, (the oldest index of share prices started in 1935) only one company (Tate & Lyle)is still there after seventy five years.

What do you think would really happen if your organisation ditched all that process and product baggage it held onto so closely? What would really happen? Are your current ways of working really indispensable?  How about your business model?  Maybe time to do some scenario planning to ask precisely those questions?

<Personal Interlude>  Eight months ago I was a lazy tub of lard. I could barely swim the length of a pool, my bicycle had two flat tyres and I’d be breathless and beaten after running 50m to catch the train. I looked for a goal, something that was outside my comfort zone, my frame of reference. I entered the London triathlon, sprint distance. Completing a triathlon became an unobtainable dream (you have to understand that I went to Loughhborogh University, home to the Jocks, [and a rather good Human Sciences department and Ergonomics course, hence my attendance there], I felt totally alienated from all the sporty types, and triathlon represented the pinnacle of pointless exercise and sport). And slowly started training for it. Running, I hated. My first swimming lesson I discovered the need to breath. Cycling, I discovered the ride to work scheme and bought myself a decent bike. I put myself on a change programme. A programme of gradual change. Baby steps. And a few weeks ago it all came together at the London Triathlon; the swimming, the cycling and the running. A multi-disciplinary effort, a radical change to my being. And I completed it. In a not overly embarrassing time; in fact I can in the top half. but better still, I ended it charged up with how much faster I could have gone, now that I know what it is like. I paced myself too slowly. I’m buzzing on triathlon. </Personal Interlude>

Organisations I see are like the tub of lard I was. Full of inertia, and reasons why they can’t change, why they can’t be triathletes.

Yeah, wouldn’t it be great to be an Apple… But we just don’t have a Steve Jobs.  Reasons why you can’t rather than inspiration, spirit and belief in why you can.

There is nothing in your organisation that is indispensable. There is no reason why you “can’t” other than your own myopia and inertia and inability to dream the future and train and practice to make it happen. All you need to do is get over the inertia and make it happen.

More often then not, people want to access the risk of undertaking an integration engagement. Small teams are called together to do a proof-of-concept.

Such an engagement is what we attempted at one of our clients. Rather than talking about risks in vague terms, we visually represented the movement on identified risk categories, on our story wall. The daily standups often included an assessment, with stakeholders, on what the attempted stories have done to minimise risk associated with each item. Luke has more about it here.

Riskmeter proof-of-concept risk assessment

Riskometer

Last week we were trying to make use of Rails' 'form_for' helper to populate a dropdown list with the values of a collection that we'd set to an instance variable in our controller.

My colleague pointed out that we'd need to use 'collection_select' in order to do this.

We want to put the values in the 'foos' collection onto the page. 'foos' is a hash which defines some display values and their corresponding values like so:

class FooController < ActionController::Base
	def index
		# @mainFoo defined with some value irrelevant to this example
		@foos = { "value1" => 1, "value2" => 2 }
	end
end

The code we need to do this looks like this:

<%form_for @mainFoo, :html => { :name=> "ourForm", :id=> "ourForm" },:url => {:controller => "foo", :action => :bar} do | mainFoo |%>
 
<%= foo.collection_select :foo_id, {"Please select"=>""}.merge!(@foos), :last, :first, { :selected => "Please select" }, {:name => "foo", :id => "foo"} %>

The method signature that we're passing those parameters to reads like this:

def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})

In this case we want the selected value to always be 'Please select' so we need to specify that in the 'options' hash. If 'selected' wasn't specified in the hash then the code would try to make the selected value @mainFoo.foo_id which in this case has no value anyway.

The other thing which I thought was quite neat is the way that you need to provided the 'value_method' and 'text_method' as parameters so that the dropdown list can be constructed with the appropriate labels and values.

In this case we have the display values as the keys in the hash and the values as the values in the hash so we can retrieve those entries from the collection by using the ':last' and ':first' methods.

We end up in the following method:

      def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
        options = collection.map do |element|
          [element.send(text_method), element.send(value_method)]
        end

This creates an array of arrays which is used later on.

In our case the values passing through this method would read like this:

        collection = { "value1" => 1, "value2" => 2 }
 
        options = collection.map do |element|
          [element.send(text_method), element.send(value_method)]
        end
 => [["value1", 1], ["value2", 2]]

I was initially a bit confused about how we were able to call the 'collection_select' method on 'mainFoo' but a quick browse of the ActionPack code showed that 'mainFoo' actually represents a wrapper around that object rather than the object itself.

好,大家写的是C++程序,那么用过virtual的,请举手!

举起的手屈指可数。



这次是系统架构的梳理,一个C++编写的大型系统,写到了添加一个新东西,自己都很难受的地步。是的,健康状况良好的系统是不会找咨询师的。



几个对系统很熟悉的人给我介绍了系统的架构,其实,它并不像我预期的那样不堪,从宏观的层面上,有着相对比较清晰的结构。我很好奇,一个还算不错的架构如何演变成今天的模样。



听完他们对于现阶段困境的介绍,我打开了代码,出现在眼前的是一大堆if,我逐渐明白了。



每次来了新需求,他们都会在现有的代码上找一个适合处理的地方,然后,加上一个判断条件,填上一大堆处理,OK,收工。下一次,又来新需求,又找到一个地方,又加上一个判断条件,又填上一堆处理。同样的事情,每天发生着。经年累月,系统成了今天的样子。



在我们看来,写完代码要重构,函数应该尽可能短小,重复尽可能少,遗憾的是,这并不是这个团队的开发人员的行事风格。



在巨大的交付压力面前,他们所能做的低着头赶代码,他们眼里,写程序就是照着别人的代码,把功能堆砌出来。他们没有时间去学习,甚至连自己用的语言都不了解:用C++的不了解virtual,写C的不知道函数指针。周边的人大多以同样的方式工作着,没有时间抬头看路的人,以为这就是天经地义的工作方式。



就是这样一支团队,日复一日的“努力”工作,系统复杂起来,于是,咨询师有了用武之地。

你是一个外来者,你想了解一个完全陌生的团队。最快的方式就是找到他们,和他们谈话,让他们告诉你。为了让谈话更有效,你会需要一些小技巧。

  • 解除他们的戒心,尽量。戒心无非来自一个很简单的原因:如果说实话不会有好处、甚至会有坏处,那么人们就不会说实话。因此你要先告诉他们,你需要快速了解信息,不是为了任何考核,只是为了帮助他们改进──告诉他们,你会在未来几个月里跟他们一起改进。
  • 话题明确。每场访谈开始之前,把你要谈的话题写在白板上,以及具体要了解哪些信息,以及计划用多长时间来谈。让进入房间的人在第一时间知道你要他干些什么,这样他就不会更紧张。并且在没话说的时候可以很快找回话题。
  • 微笑。有很多人说过这事,可是真的有很多人没有做到。微笑,活泼一点,拿自己开个玩笑(例如嘲笑自己刚在白板上写下的字)。在访谈中你会必须制造紧张气氛(例如你会有意指出两个人对同一件事的不同描述),保持微笑,把它变成一件好玩的、和所有“人”对立的“事”。不要让任何一个受访者感到寂寞或者紧张,因为这时候你还不知道究竟谁才是值得信赖的人。
  • 记下别人说的话。更多的人说过这事,可是我们真的做得都不好。不要一边跟人对话一边在记事本上写字,更不要用电脑做记录。这些行为会让你获得权威感,会让受访者感到不安──“他有代表权威的记事本/电脑,而我仿佛裸体”──甚至为了抵抗这种不安也拿出记事本来写字。但这些行为不会帮你得到更多有效的信息。在白板上做记录。把他们说的事情画下来。这会让受访者感到,你们在一起画一个作品。他们会告诉你,什么地方画得不对,还缺少了什么,这是你的记事本上永远不会出现的东西。
  • 问他们有什么想告诉你的。当你问完了所有的问题,问他们:还有什么想告诉你的,有什么问题,有什么痛点。你在这里的原因是你要帮助这些人。这些人最关心的事不一定是你最高优先级的事,但一定不是你应该忽视的事。
  • 最后,不要相信访谈。用眼睛去看。受访者一定会告诉你假话。有这样的觉悟之后,访谈才会真正是有效的。
Although at very beginning TDD, especially the UI part, looked challenging on Android, now after about 90 tests and 4,5 epic stories, I am comfortably to say that Android app can be developed in a TDD fashion reasonably smooth. You just need to accept that you can't test the interaction between UI and domain model using mock framework. Then you design in a way so that such need will be reduced to minimum. Some Android API might not be test friendly, you can solve that by introducing some middle layer abstraction.

We’re fortunate to be having John Seddon keynote at our internal conference in a few weeks so I wanted to read some of his material in advance. I bought the Freedom From Command and Control book out of interest to see how he applied systems thinking to the service industry.

Depending on what your background reading has been, it may or may not be heavy going. I really appreciated the background I’d done in reading about lean thinking, systems thinking and other respects so I found most of my interest seeing how he viewed the application of these tools, rather than the description of the tools themselves.

Despite some warnings from a number of people, I found the book easy to digest – made all the more entertaining by the repetitive (in a good way) and controversial statements thrown in the book. I figure Seddon wrote them in to intentionally jar your traditional manager into thinking differently.

My biggest takeaways follow:

Stop creating failure demand – Lean thinking looks towards the end-to-end flow of value – starting from customer demand. Seddon articulates on focusing on the idea of shaping the demand and service organisations often get to choose what sort of demand they have (to a degree). More often than not, organisations instead flex their capacity to meet all demand – not really spending the time to think about whether or the demand they have is what they want or not.

For me, this links into another view such that organisations need to address bigger root causes, improving quality and experience for customers to stop generating failure demand. I see these ideas equally apply in a software context – many of the practices we adopt is intended to build quality in from the start so the development effort can be focused on helping the flow of business ideas, rather than spending time on fixing “defects” for customers that should not have reached them in the first place. Similarly, properly addressing user experience early enough will help to prevent failure demand.

Reaffirmation that arbitrary targets are bad – Seddon isn’t fearful to state his view around the idea that setting targets are bad – in that, you get what you measure and the targets are often not really related to the purpose of the system. This seems to sit well with the discoveries of the Beyond Budgeting Movement who’ve realised you cannot use the same instruments for measurement, planning and setting goals (decouple them!)

I found interestingly Seddon still explain to people the importance of measurement, just not arbitrary ones that managemet set and then create systems around.

Using Capability Charts to map demands – Seddon describes the capability chart as a way to visualise the way demand is being generated. Its focus on visualisation is a way of helping people to see natural fluctuations in a system and a way of identified trends not easily seen when boiled down to a matrix of numbers.

Look down. Look up again. You’re on the agile team your team could be like.

It’s the end of the iteration, and there’s a showcase this afternoon (sprint demo if you prefer) demonstrating all the new functionality the team has built in the last two weeks. In the room are members of the project team, the product owner, and various stakeholders and interested parties from the marketing and customer service teams who use the product every day. Everyone’s very excited about the new features, and provide some great feedback on the spot.

This sounds great! But something is missing. Where are the ‘ops’ features?

Very few agile projects I’ve been on will demonstrate the ‘cross-functional’* or ops features they’ve completed in the same showcase, but they SHOULD. Features like monitoring, failover testing, deployment automation, performance improvements – these are all very important to our business. If you’ve truly got a DevOps culture, then they should be showcased and celebrated alongside the new whizzy UI features.

How do we make these achievements relevant to a wider audience? Start by describing the work in a different way – talk about the work that’s being done in terms of its benefit to our business.

A technical story would look like:

Enable monitoring of JVM heap allocation.

To make it more understandable to the business, highlight the business benefit in this way:

In order to reduce the risk of an outage as site traffic grows

The operations team need to

Monitor the JVM heap memory allocation

By putting the business benefit up front (and always present) this should help make the story more interesting to showcase.

The regular showcase presentation is also an opportunity to report to the stakeholder group on the current state of the system in production. This can take the form of presenting some selected metrics plotted over time. For a website you might include metrics on site traffic, response times, performance and stability over time. The presentation should support the prioritisation of appropriate cross-functional work to improve those metrics over time.

Getting to the point where cross-functional work is celebrated by a wider stakeholder group requires some creativity and effort. When it works I’ve observed it makes the conversations around proper prioritisation and collaboration on DevOps work so much easier.

* I’ve taken to using the term ‘cross-functional requirements’ (thanks to Sarah) to describe requirements that are cross-cutting and not-directly-functional – for example performance, availablity, volume, maintainability. I think the term NFR has become a weasel-word, treated as ‘someone else’s problem’ rather than an important priority. It might just be a word game, but I think it’s useful.

The other day, in a meeting, someone made reference to the change process as a plow. At that moment, I admit that I stopped listening. Not because it wasn’t interesting or valuable, but because the image of the plow took over my attention.

First, the question of pulling, pushing, resistance, and steering. This intrigued me. When we focus on organizational transformation (or whatever term you like), all four things come into play.ox-plow-nepal.jpg

Pull

The pull comes from the organization’s desire to change. The power of the pull, then, is dependent on their desire and willingness and commitment. Imagine the image at the right – strong desire, willingness, and commitment. Now imagine a chihuahua pulling the plow. Would you achieve the same success in the same time? Probably not.

How about the idea of a plow that is pulled, but not pushed or steered. How would it be if the oxen were left to their own devices here? The plow would fall over, and either they’d keep going until they got bored, or they’d get stuck because the plow got stuck on something.

The importance of pull is that it’s nearly impossible to achieve change without some amount of pull, while at the same time, pull is not enough by itself.

Push

train_plow.jpg

Then let’s consider push. Many of us approach our consulting/coaching roles as if our job is to provide a giant push. This just doesn’t work. If there’s no pull, then no matter how hard we try to push, we’re not going to achieve success quickly. Imagine a cruise ship or one of those massive oil tankers. Yes, their default mode of propulsion and steering is from the rear – push. It takes a long time to change the direction of a ship like that, because of the inertia of the ship and the resistance of the water.

Now imagine adding a tugboat at the front of the ship. While neither push nor pull is enough by itself to make a significant change quickly, working together they can effect the change more quickly than otherwise.

So we have the idea of synergy between the organization’s pull, and the change agent’s push. Together, they produce more change more effectively.

Of course, with pull and push working together, you get a linear motion, right?

Resistance

No matter how willing individual people might be, there will be resistance. Sometimes it’s passive resistance: people just keep doing what they’ve always done, not to thwart the change, but because it’s what they know. Sometimes it’s active resistance: people hold fast to their kingdoms or their safety, and change is threatening. Regardless of the reason, there will always be some resistance. In plowing for planting, it’s the earth itself. In the example of our ship, it’s the water. Neither earth nor water is actively resisting, nor is it malicious. Rather, just like organizational processes, water moves in its own way and earth is static in its own way, and you have to work with it rather than against it in order to succeed in effecting change.

Steering

Finally, let’s look at the part that brings them together: steering. Pull without steering is inflexible. The ship will keep moving in one direction. Push without steering is unpredictable. Whether the vagaries of the waves (change) or running into some resistance, pushing can lead to disaster. Consider the Titanic. While they had push and steering, they didn’t apply the steering until it was too late.

And, of course, there are currents in the water that change, and rocks in the ground that resist progress. It takes some attention and thought to recognize and adapt to those currents and obstacles.

We have to consider, therefore, that change is best effected by a combination of pull – the desire to change, push – the drive and incentive and energy, and steering – the intelligence and experience and attention to make decisions on a moment-by-moment basis.

When we find ourselves in coaching/consulting roles, it is a significant challenge to find the balance, and to find the right people/groups to effect that balance.

  • Oxen pulling plow: http://www.hobotraveler.com/2007/02/nepal-plowing-field.html
  • Train plow: http://www.flickr.com/photos/mclaren237/3101440372/

Post to Twitter Tweet This Post

Share/Bookmark

Related posts

The majority of organisations I’ve worked with deliver new system functionality as development projects.  These are funded with capex, and have a start and an end.  Even projects that are ‘agile’  are still expected to finish at some date in the future, then once the system has been delivered it will undergo ‘handover’ to ‘BAU’.  The project team usually moves on to new projects, developing remarkable cases of mass-amnesia along the way.

Projects deliver exactly what they promise.  Project teams have little incentive to invest in the long term operation and maintenance of the systems that they create. I’m not saying that the team doesn’t care or are intentionally acting irresponsibly, but when delivery pressure is applied the first things to be dropped from the project schedule will be the cross-functional concerns that make the system reliable, monitorable, deployable, and maintainable ongoing.

The project effect:

  • the project team do not have to live with the long term results of their own architectural and design decisions.
  • BAU support/maintenance teams are generally under-resourced, have extremely limited opportunity for handover from project teams, and have to support many different systems.  This usually leads to less than ideal development practices and deteriorating quality over time.
  • the project team never have to be involved in problem analysis for production outages.  They’re never forced to put the right kind of monitoring and logging in place to find root causes.
  • the project team only do a limited number of releases to production, so have little incentive to invest in reliable automation or production-like test environments.

Therefore – I believe that many projects are the source of ‘instant legacy’, and a major cause of the development and operations divide.

What’s the alternative? Form long-lived teams around applications/products, or sets of features.  A team works from a prioritised backlog of work that contains a mix of larger initiatives, minor enhancements, or BAU-style bug fixes and maintenance.  Second-level support should be handled by people in the product team.  Everyone in the team should work with common process and a clear understanding of technical design and business vision.

This approach is not easy – it introduces new challenges particularly around balancing priorities and budgeting.  I’ve observed that the benefits in terms of long term system health definitely outweigh the drawbacks. Like everything – hire good people who care, and give them the right incentives, good things will happen.

Ruby Kaigi 2010 – Rocking the Enterprise with Ruby

Uploading the beta version of the presentation for today’s ruby kaigi talk.

Rocking the Enterprise with Ruby(Keynote)

Rocking the Enterprise with Ruby(PowerPoint)

Be virtually there!

So I was looking for two DLL's to get Log4Net working with Windsor 2.0. I had a hard time finding the version I needed, as I guess I'm in the dark ages not using Windsor 2.5. The files in question are: Castle.Facilities.Logging.dll and Castle.Services.Logging.Log4netIntegration.dll Why am I using Windsor 2.0? Since the version of FluentNHibernate I'm using is 1.1 and uses CastleDynamicProxy2.

Over the next couple of months, Jim Webber and I will be running several day-long REST tutorials:

  • Following JavaZone, we’ll be at Oslo’s Henning Solberg on Friday, 10th September. You can register for JavaZone here, and for the tutorial here.
  • At the beginning of October, we’re at the wonderful JAOO Aarhus, with the tutorial running throughout the day on Friday 8th October. Register here, with a 20% discount if you use the JAOOspeakerfollower promo code.
  • Closer to home, we’ll be at Software Architect 2010 in London on Friday, 22nd October. You can register for the conference and tutorial here.

The tutorial agenda closely follows the structure of REST in Practice, which hits the shelves on Sept 24th:

  • The Web Architecture: HTTP and URIs
  • The Richardson Maturity Model
  • CRUD Services using URI templates and HTTP
  • Hypermedia and the REST architectural style
  • Implementing domain application protocols
  • Atom- and AtomPub-based event-driven systems
  • Scalability through caching
  • Semantics using Microformats and RDF
  • Security and the -ilities

With ThoughtWorks recently having opened an office in Germany, I’ll also be presenting at Herbstcampus in Nuremberg, 12-15th October.

And finally, if your want to enjoy some REST in Practice from the comfort of your own office (or home), there’s still time to sign up for the ThoughtWorks’ Webinar, Designing and Implementing RESTful Application Protocols, which takes place on Wednesday, 1st September, at 6.30pm IST (that’s, er, sometime in the afternoon GMT).

A week or two ago I attended the Open Space Coding day arranged by Alan Dean, and held at the Conchango offices. The Alt.Net community is very good at getting together and talking about code, software, and how it should all be done, but the focus of this meeting was to get on and write [...]
Why do Ruby developers brag about true OO vs Class based OO?
This post is in response to Tim Ross’s post on ‘Are Burndowns Evil?‘ Tim asks how useful a Burndown chart is, especially in the case of a new team with a new or unknown code base. A burn down chart (with an ideal line) for a new team immediately gives a team ‘schedule pressure’. Some may [...]
One of the great things about Agile software development that I’ve noticed is sustainable pace. Planning poker, point based estimation and velocity are all great tools for finding a team’s sustainable pace. Knowing a team’s velocity and consistent estimating by the entire team, allows a team to commit to as much work as it is [...]
In an effort to get our teams understanding ‘Done Done’ we’ve started looking at acceptance testing. We’ve moved, over the last 18 months or so, from a traditional waterfall process to a full on Agile one, our final hurdle is the QA process. We still have a very waterfall-esque QA approach. We’ve done lots in [...]
Following on from my entry on the altnetuk session on Agile Process, I’m just going to layout the different types of estimating with points that I know of. I’m not sure why but at that session it felt like someone had put and end to point to complexity estimating and forgot to let me know! [...]
So to start the conference I chose to take part in a session about agile development and processes. I think mainly because I wanted a refresher on some of the points and to see if I could contribute. It’s nice to see plenty of people there new to Agile as I was at my first [...]
So, I’ve just got back from the altdotnet conference in London. This is my second altdotnet conference, and it was as good as I remember. You could see people had moved on, and it was nice to see that altdotnet has had its affect on uSwitch.com in a positive way. 5 attendees were currently employed [...]
My first blog post on this wordpress site. How exciting, I’m trying to get other the initial, “I’m not worthy of publishing my thoughts” thing that I’m sure all those that blog need to get over, so please bear with me. I’ve also got to keep my sentences shorter! Hopefully, I’ll be able to use [...]

I work at ThoughtWorks Studios, where I am product manager for Go (our continuous integration and release management platform, of which more in a future post), and a general big mouth about build and release management. As part of the launch of the book and of Go 2.0, we’ve created some collateral you might find useful – a white paper on release management and a build and release management assessment.



The white paper, “Agile Release Management: Towards Frequent, Low-Risk Releases” (warning: registration required, but it’s free) is actually a pretty good summary of many of the things Dave and I discuss in the book, so worth checking out if you want to have a brief overview of our approach to the problem of getting software live in medium and large organizations. It’s also a useful summary if you’re trying to introduce continuous delivery to management.

We’ve also created a multiple-choice assessment that grades your team’s maturity at build and release management according to the model we present in Chapter 15 of the book. The final report you get when you complete it includes a table which lays out the maturity model. There’s also a more general agile assessment at the same site.

While a multiple-choice assessment obviously can’t replace a serious investigation of your organization’s capabilities, strengths, and weaknesses, it is a useful starting point in such an investigation. I was happy to hear Dave Thomas talk about the importance of assessments in his Agile 2010 keynote – doing an assessment is step one in his list of how to do an agile transformation programme (and the rest of the list has a lot in common with the material we set out in our book).

Although they’re created by ThoughtWorks Studios, both the white paper and the assessment are vendor neutral. There is of course advertising for the book and the ThoughtWorks Studios ALM suite at the end, because hey, we’re proud of our stuff.

If you have any feedback or want any further information, please feel free to leave a comment.

One of the earliest rules of thumb that I was taught by my colleagues is the idea that we should try and avoid mutating/changing values passed into a function as a parameter.

The underlying reason as I understand it is that if you're just skimming through the code you wouldn't necessarily expect the values of incoming parameters to be different depending where in the function they're used.

I think the most dangerous example of this is when we completely change the value of a parameter, like so:

public class SomeClass
{
	public BigDecimal doSomeCalculationsOn(BigDecimal value) {   
		value = value.divide(new BigDecimal("3.2"));
		// some other calculation  on value...
		// and we keep on re-assigning value until we return the value
		return value;  
	}
}

In this case the function is really small so maybe it doesn't make that much difference readability wise but I still think it would be better if we didn't reassign the result of the calculation to 'value' but instead used a new variable name.

It wouldn't require a very big change to do that:

public class SomeClass
{
	public BigDecimal doSomeCalculationsOn(BigDecimal value) {   
		BigDecimal newValue = value.divide(new BigDecimal("3.2"));
		// some other calculation  on newValue...
		// and we keep on re-assigning newValue until we return the newValue
		return newValue;  
	}
}

Unless the function in question is the identity function I find it very weird when I read code which seems to return the same value that's been passed into the function.

The other way that function parameters get changed is when we mutate the values directly. The collecting parameter pattern is a good example of this.

That seems to be a more common pattern and since the function names normally reveal intent better it's normally less confusing.

It does become more problematic if we're mutating an object in loads of places based on conditional statements because we can lose track of how many times it's been changed.

Interestingly some of the code for ActionPack makes use of both of these approaches in the same function!

form_options_helper.rb

564
565
566
567
568
569
570
571
      def to_collection_select_tag(collection, value_method, text_method, options, html_options)
        html_options = html_options.stringify_keys
        add_default_name_and_id(html_options)
        ...
        content_tag(
          "select", add_options(options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => disabled_value), options, value), html_options
        )
      end

form_helper.rb

        def add_default_name_and_id(options)
          if options.has_key?("index")
            options["name"] ||= tag_name_with_index(options["index"])
          # and so on
          end
        end

I'm not sure how exactly I'd change that function so that it didn't mutate 'html_options' but I'm thinking perhaps something like this:

	def create_html_options_with_default_name_and_id(html_options)
          options = html_options.stringify_keys
          if options.has_key?("index")
            options["name"] ||= tag_name_with_index(options["index"])
          # and so on
	end

And we could then change the other method to call it like so:

      def to_collection_select_tag(collection, value_method, text_method, options, html_options)
	   html_options_with_defaults = create_html_options_with_default_name_and_id(html_options)
        ...
        content_tag(
          "select", add_options(options_from_collection_for_select(collection, value_method, text_method, :selected => selected_value, :disabled => disabled_value), options, value), html_options_with_defaults
        )
      end

I guess you could argue that the new function is doing more than one thing but I don't think it's too bad.

Looking back on these code examples after writing about them I'm not as confident that mutating parameters is as confusing as I originally thought…!

The opensolaris governing board has resigned, thereby handing control of the community to Oracle.



The OGB has done a good job in so far as their powers as a Governing Board are concerned. Before one declared them to be "weak" or "powerless", we should remember that most of them are strong enough to run their own distros. Indeed, Moinak created Belenix, and didn't hesitate to quit Sun when the pressure to stop work on Belenix became too disappointing (among several other reasons).



If Oracle really believes in community, etc, then this is the time for them to put their act together. After all, one of their VPs - Jeb Dasteel - has said in writing from an oracle.com email address that Oracle is interested in the community.



Surely Jeb must have some worth of his own words both as a senior Oracle officer, and as a senior person in the industryu.



Also, Oracle must have some self-respect of their own so explain their VP's statements and promises to the community.
I've always held that the OpenSolaris distro is different from the opensolaris community and code base.



There's been no formal communication about what Oracle intends to do with the opensolaris community + codebase. Leaked mails, news from friends within and from vendors did give a number of us insights into what's happening around.



If one were to go by the leaked email then the distro is dead and the mercurial repo will get some code pushed to it (under the CDDL license) only after Solaris 11 is release.



Circumstances may change in the future, and Oracle may push through nothing at all.



Rather than whine about source being closed, or Oracle reneging on promises made in Feb, I'd rather thank Sun for releasing the excellent code to the world, and congratulate them on putting together an engineering team that created such amazing functionality !



Thank you, Sun, and thank you, all you Sun engineers who created such wonderful work.



I just cannot use a Linux based distro full time ever again.
Just thought I'd let the world know that we've got rpm working on Belenix this weekend. We're able to use rpmbuild to generate packages, and I'm running most of my custom stuff as rpm installs :)



There was a curious issue with rpm (my usual mis-build karma, I think), so I got rpm5 in place instead.



smart's working as well, but there's some testing in progress more to do with me understanding smart better.



I haven't touched yum yet, though, since smart's more exciting at the moment :)



So just in case Nexenta's Debian-alignment doesn't work out, we have a plan B at least (though I'm myself partial to rpm, to Centos's stability, and to Fedora's clean new packages).



What fun !

In June I gave a talk at Agile Brazil. During the conference my colleague Paulo Caroli and I were grabbed to give an interview for InfoQ Brazil. We touched on several topics: acceptance testing, polyglot programming, my DSL book, REST, and continuous delivery.

Disclaimer: ThoughtWorks embraces the individuality of the people in the organization and hence the opinions expressed in the blogs may contradict each other and also may not represent the opinions of ThoughtWorks.