Cargo Bike Lifestyle

The Cargo Bike: Bullitt by Larry vs Harry

Larry vs Harry is a cargo bike maker based in Denmark, and Bullitt is the name of their flagship cargo bike.  They offer e-assisted and ‘manual’ versions (I’m fortunate enough to have the former).  You can see lots of great pictures that give you a broad sense of the bike on Instagram – links at the bottom.

DSC_0837

How Does It Feel?

It handles really well.  It’s essentially the longboard of bicycles.  The front-loading cargo deck configuration means that the center of gravity is kept low (stable) and loads are visible (safer).  The cargo deck is still relatively narrow (less than the width of the handle bars) so it’s relatively streamlined and can still manoeuvre through tight traffic.

Basically the Bullitt is a great example of great European design: functional, elegant and balanced.

It is rated to carry 180 Kgs including the rider, which equates to you and a small truckload of groceries and or children.  My heaviest regular load is the weekly market shop for fresh fruit & veg (~20-30 Kg’s worth?) – more on that later.

As you can see, it’ll accommodate a wide variety of load types and can be used in a number of ways.

It goes fast.  Bullitt’s are equipped with the Shimano STePS system, which will assist you up to ~25 Km/h, after that it’s up to your legs and/or gravity.

Battery & Motor Performance

To understand this some local context is needed.  My daily commute is just over 4 Km, of which 3.3 Km’s of that is a steady 150 m vertical ascent (heading home).

The battery lasts me 5-7 days, based on approx. one return trip to town a day (x7), and depending on how much additional riding I do.  The journey home usually drains ~10-12% charge depending on how charged it is.

The STePS system has 3 assist modes: eco, normal, high, as well as no assist.  I tend to ride with the e-assist off except for when going up-hill or into a string head-wind.  Unless my load is especially heavy (or my knees are feeling particularly weak) I’ll stick to Eco-mode assist for the normal commute home.

According to the specs a full charge will assist you for 145 Km on the flat, for comparison High will assist you for 65 Km.  I tend to use eco to get better endurance, and frankly the extra power achieved by the more powerful assist modes isn’t something I find I need – but it’s good to have it in reserve.

Loads & Configuration

My goal is never to carry anything on my back ever again; I want to maximize the bikes ability to carry stuff and my own comfort.  I’m also keen for my configuration to be as flexible as possible.

My solution to this is:

  1. Flat open deck – no permanent / fixed side walls.
  2. A pair of large fish bins (approx. 41 x 64 cm) with lids for general cartage.
  3. A pair of army surplus ammo pouches for small items.

The bins have the same width and length but slightly different heights (28 cm & 19 cm), the idea being that the variety might come in handy.  They both have (interchangeable) lids which provide adequate protection from rain.  Depending on their relative orientation they can stack on top of each other or sit nested inside each other.

I have sliced up a foam camping mattress for padding – you can see it lining the front bin in the picture above.  A single layer of this seems to protect fruit adequately, as well as laptops, and you can always use a double layer (I got three sections from the one mattress).  The foam also helps raise your items off the very bottom of the bin, so if any moisture does make it inside your stuff is less likely to get wet.

The bins can be used a number of configurations:

  1. Stacked on top – as seen in the first picture above.
  2. Stacked within each other.  If the taller bin is placed in the lower one you get one big bin with the ability to expand out if you need the extra capacity.  f you stack the lower bin in the taller one you get a split level; e.g. you can put laptops and other ‘nice’ things in the bottom and other items in the top -like wet raincoats, dirty boots or whatever.

Bindings:

I have two cargo-straps: 1 x 3m and 1 x 4m.  The 3m will comfortably loop around the cargo deck and both bins top-stacked.  (Note: the strap needs to pass between the frame and the steering rod as you don’t want to impede the steering rod).

The 4m strap will comfortably to a double “n” loop over both bins high-stacked.  This is the configuration I am most using currently.  Imagine the loop starting at the top of the load – it passes down one side, goes under the frame and back up again; down the opposite side, under the frame and back up again, where it completes the loop.  This technique give s nice firm double strap.

Above: showing the double “n” loop, and an ammo pouch for small items.

I also carry two lengths of 6mm rope from the local marine supplies shop, which is great for random stuff.

Above: for comparison – the shorter fish bin inside the taller one; and “high stacked”.

Finally, I also have a few rubber bungies, these are made from recycled car tyres with a bit of dowel for a handle.  Basically you just need to carefully cut an intact cross-section so that you have a nice strong loop of rubber, and then loop one end around the dowel and back through itself (a little bit like the first step of tying a cats-paw knot).  You can extend these by hitching a second loop onto the first (like the longer of the three bungies, below).

WP_20191004_19_02_21_Pro

The only minor pain is that with strapping stuff in I’m frequently forgetting things – either that I should have out, or need to put in, so I find myself messing about with straps and so on a bit.  But on balance its a pretty minor problem to have.

Manoeuvrability

You’d think the longer wheel-base was a challenge – actually it’s not too bad, but you’ll want to be a little more conscious when planning stop-offs so that you can avoid having to do U-turns on the footpath.

The biggest challenge I find is inner-city stops where you want to change direction – you can pick up the rear of the bike and pivot on / manoeuvre with the front wheel easily enough, the only real challenge is available space.

As you can see in the video below, slow cornering around tight corners is no problem provided there’s enough space.

In terms of slow riding, I can stay upright doing as little as 4 Km/h.  The relative size of the wheels to the overall bike means the ratio of gyroscopic force the wheels produce is not as great.  But in general the Bullitt is really well balanced and great to ride.

Have I Ever Fallen Off?

Just the once.  It’s hard to pin-point the cause exactly.  It was early on in my Bullitt days, doing a sudden lane change on a wet smooth road.  There was a gap in the traffic and a car was offering me entry into the far lane.  I had both bins high-stacked with a bunch of gear.  I turned into the lane and rode across it, then sharply turned to straighten-up and the bike flipped over on it’s side and slid.

Did I hit a patch of oil?  Impossible to tell.  I think it was partially the sharpness of the turn, the wet conditions, and perhaps overall speed – not super fast but not hanging around either.

Once I fell I was pretty much just tobogganing along, the nature of the frame meant I was somewhat lifted off the ground by the mid-frame “h” shape off the handlebar stem, so apart from some minor scuffs I was unhurt.

Interestingly, I had the fish bins lashed down with a single cargo strap and they were totally intact – didn’t really move at all, so picking the bike up again and clearing the road was pretty easy.

Conclusion

Front-loading cargo bikes are super versatile, possessing good speed and manoeuvrability but with prodigious carrying capacity.  The Bullitt is an awesome example of this architecture of bike, and makes for a great car replacement.

References

  1. http://www.larryvsharry.com/ – designers and manufacturers of the Bullitt.
  2. https://www.shimano-steps.com/e-bikes/europe/en/product-information/city-trekking/e6000 – more information on the Shimano STePS system, 6000 series, which I have mounted on my Bullitt.  Various Bullitt models use different versions of the STePS system.
  3. https://www.bicyclejunction.co.nz/ – local Wellington Bullitt dealers.  They also carry other types and brands of cargo bike.
  4. https://www.youtube.com/watch?v=hGPl3HPPotY&list=PL-oWnHyIj78AIrTyp9gTUnRd9iNKMEv1i – The Adventures of Pepper the Cargo Bike; me & Pep’s cruisin’ around Wellington and beyond.

Fireside Chat with Zheng Li, VP of Product @ Raygun – Product Tank Wellington MeetUp

The Product Tank Wellington meetup ran a “fireside chat” last night with Zheng Li, who is currently VP of Product with Raygun – a Wellington-based company, currently on loan to the U.S.

The conversation covered her career path to Product via UX, advertising, championing women in tech and passion for business, as well as delving into specific topics with being a product person.

Here are the key takeaways I jotted down, which I’ve tried to organise by topic…

Career Path

Zheng gave us a neat little story about how she started out (in a sense): a classic tale of taking something that nobody else wanted to do and absolutely nailing it.

The task was designing banner ads for TradeMe.  She obviously attacked her self-imposed challenge with passion and drive (significant keys to success on their own), but I also noted that:

  • She formed a loose multidisciplinary team which (I think) included people with knowledge and access to data analytics and marketing folks.
  • Was data driven – each time she/they ran a new design, they would analyse the data to see what was working and what wasn’t, and think about why that was the case.

The other factor which she used to her advantage was being able to iterate at an appropriate speed – which was obviously supported by the data she and her team had access to.

Some pretty obvious takeaways there, a key one for me would be about being data driven / enabled > implication: you need to have the data.  As a data architect colleague of mine once said: before doing any data design, you must first think about what questions you will want to ask your data.

Other stand-out points around career path included:

  1. Turning weaknesses into strengths, by using them as differentiators.  The context for this was around credibility.
  2. Follow your passion.  Zheng laughed in response to a question – someone asked something which inferred she had planned her career out; she said that in retrospect her career may look like it was planned but the reality at the time was anything but.  Her response to challenges was to consciously seek out ways of addressing these – which in her case frequently included training courses, which she collectively found effective (I think for one particular area she did 7 different courses).
  3. People want to work with people they like and trust.  Zheng spoke of this in reference to relationships between companies, but it’s obvious from her perspective that this is based on interpersonal rapport.  It’s not hard to see this concept also applying at a personal career level – something I can attest to having also experienced it first-hand.

Another key career theme Zheng had was based on “that venn diagram” – meaning the three overlapping lenses in Design Thinking which cover business/viability, technology/feasibility and people/desirability.  The specific terms she used might have been a little different, but for me the connection was pretty clear.

Her basic advice was to become proficient and confident in any two of these lenses; although that seemed to be somewhat tempered with her other guiding principle of being customer focused – which suggests the business/viability and people/desirability lenses.

“Product” Means Being Close to Customers

This was one of Zheng’s key themes.  Part of this was getting out and talking to customers, which is critical.

It was interesting to hear of her experiences using product “management” (my term, not hers – can’t recall exactly what she called it) as a selling tool.  The basis for this was:

  1. Selling the value of the product, not the product.
  2. Establishing a 1-on-1 rapport with people, and understanding what kept them up at night.
  3. Taking the time to really understand that problem from different angles.

As far as point #3 goes, that meant engaging with different people in the organisation to understand the problem from their perspective: technical, marketing, sales, etc; this obviously links back to the three lenses of design thinking mentioned above, and being close to customers – all good sensible product management stuff.

We can also expand this theme out “customers” to “people”.  In her experience, product management is more about being people-based than technology based (this was mentioned in reference to a technical product for developers).

There was also a leadership angle: for her leadership was about aligning the purpose of her staff to the purpose of her business.  The implication here is to talk with the people on your team and really understand what drives them and where they want to go with their career.

A Quick Note on Persuasion

If you want to persuade someone (such as your product manager – if you’re a tech working on the product, and you have a pet feature you want to add), you need to two things:

  1. Speak in the language of the audience.
  2. Back it up with data.  This could be qualitative such as customer feedback, or quantitative data showing conversion rates.

Producty Bits

Dealing with Product Debt

Something I really liked was how she addressed debt – debt in the sense of technical debt, and even marketing debt, and so on: things which worked but could work better and had gotten to the point that they were affecting the bigger picture.  She referred to it (I think) as the “99 issues” or “99 problems” story.

  1. They got all the issues and logged them into Jira – meaning that they got it all out into the open.  Not just development/technical debt, everything.
  2. Presumably some sort of sizing and prioritisation work took place.
  3. They then knocked off a number of the items, reducing the overall debt.

The way she spoke seemed to indicate this was an annual event – which didn’t happen every year.  Bit of a spring-clean, I guess.  Zheng didn’t call it out specifically but based on her other comments I presume space in the teams capacity / product roadmap was allocated to this work.

Another interesting idea which occurred to me as she described this was the technique that Agile / Scrum teams sometimes use, whereby they adopt a sprint goal – something non-deliverable – that they want to improve during the course of the sprint/iteration/timebox.  Zheng didn’t explicitly say that was what they were doing but the idea seems relevant.  Zheng, if you ever read this I’d be interested to know if that concept was one you consciously used or were aware of.

Roadmap

Items on a roadmap (i.e. the implied promise / expectations set) should be based on two things:

  1. The teams capacity to deliver them.
  2. Evidence that a given feature is wanted by customers.

Pushing Back

Don’t be afraid to push-back.  If a customer requests a feature (for example) that  is outside your roadmap and/or ability to deliver then be wary of following the money.

This definitely fits with my experience; I tend to think that at a inter-business level or interpersonal level, the relationship needs to be built on mutual trust and respect – if the other party does not reciprocate then they’re probably not someone you want to be dealing with.

Zheng gave two examples:

  1. A major multinational effectively tried to bully their 50 wanted features on top of Zheng’s existing product roadmap – “you want our business or not”?  To have done so would have caused massive chaos within the company, affecting product delivery and so on.  Zheng counter-proposed a different approach which she and her teams could sustain.  The multinational rejected the offer and went elsewhere – only to return months later, accepting Zheng’s proposals.
  2. Another major company approached Zheng with features (she didn’t give specifics but I think we can guess their approach was more reasonable and more adaptable).  Zheng recognised that some of these features would be great differentiators for their product, so (presumably) some changes were made to the product roadmap and the featured added – in essence Zheng followed the money,  but did so because there was further advantage than just the money.

Final Thought: The Iron Triangle

At one point Zheng told an anecdote about a developer talking with her about code quality.  I forget the story but it reminded me of the the old “Iron Triangle” or project management triangle – the one that is made up of scope, quality and cost (or some similar combination; cost and time obviously being closely related).  The model effectively states that you can control any two; the implication being that if you nail people down in terms of scope and cost (or time) you have no control over quality.

I asked Zheng if she was familiar with that model and how she approached it.  Her answer wasn’t as clear-cut and direct as I would have hoped (which is not a criticism – having presented publicly I know how hard it is to provide an off-the-cuff answer that is cohesive and concise), but seemed to boil down to this:

  1. Her first substantive reaction was to discuss scope and features, so I would guess that this is her first priority.  This would align with her other comments that put great importance on being close to the customer and understanding their needs.
  2. Her second substantive reaction was to discuss product roadmaps, specifically in reference to their timing and how they are used as the basis for cross-team coordination (marketing and so on), so I imagine time would be her second priority.

By default this would leave quality to manage it self; but we shouldn’t forget the “spring clean” approach, whereby random items of debt (arguably involving quality) can be addressed in a structured way.

 

 

Uber Fail

I wouldn’t normally pollute the internet with stuff like this, but I always tend towards the cynical when much feted, “tech-savvy”, market defining, paradigm shifting companies show us that their mastery of technology and process is really no better than anyone else’s.

Firstly, I was on the Uber website and accidentally started the process of registering as a driver – which was not what I wanted to do.  My bad, I admit that; anyway usability of the website’s not the main focus here.

I soon start getting SMS message’s as part of the “new driver” process.  Ooops, I had better reply STOP to unsubscribe…

Oh dear, did anyone actually test that unsubscription works, or do you:

  1. Have shares in the Telco industry
  2. Forgot to implement it
  3. Deliberately not implement it

wp_ss_20170501_0001wp_ss_20170501_0002wp_ss_20170501_0003wp_ss_20170501_0004wp_ss_20170501_0005wp_ss_20170501_0006wp_ss_20170501_0007wp_ss_20170501_0008

But we’re not quite done yet.

I’m not just getting enduro-spammed via SMS, this is a multi-channel affair:

uberemail1

Although the email campaign has it’s own issues – nothing major, just the occasional missing subject line and total absence of any content.

Oh, but at least the template is nice.

uberemail2

@Uber #STOP

 

WSAF Survey 2015 – Results

A while back we put a survey questionnaire to the architect community via Meetup.com and LinkedIn, which included questions such as:

  1. How long have you been in IT?
  2. How long have you been an architect?
  3. What Title best describes you as an architect?
  4. What did you do before you became an architect?
  5. Career progression: what role do you aspire to move into next?
  6. What is your biggest challenge as an architect?
  7. Do you feel you are effective as an architect?
    • Why? Please tell us what you feel makes you effective / ineffective as an architect
  8. What advice would you give to new / aspiring architects?

Despite having 680 WSAF members on LinkedIn, and 142 on Meetup.com we only managed 10 responses.

In some ways it was far less than we were hoping for – given our numbers on paper.  I do acknowledge that as organizers of the group, the WSAF isn’t perhaps as active as we’d like to be, however, it might also be a reflection of  the local kiwi architect culture, and symptomatic of the channels we currently use to reach you all.  Community engagement is an area we are conscious of and something we’d like to increase in future.

The Results

Whilst the low response rate may render the quantitative results less than statistically sound they did provide some interesting insights.  Some of the questions were more qualitative provided some quite thought-provoking comments.

You can download the raw results here: https://onedrive.live.com/redir?resid=2942088AAC497628!4940&authkey=!AJstOf7P6LaCOZU&ithint=file%2cxlsx

[The results (xlsx) and images posted here are hosted on Microsoft OneDrive, let me know if you are having trouble accessing them.]

Who Responded?

In terms of roles most of you were, unsurprisingly, Solution Architects or Enterprise Solution Architects:

Title

How Long?

  • How long have you been in IT?
  • How long have you been an architect?

As you can see, most of the respondents have been in IT for 10 years or more, in fact mostly for 16 or more; but a relatively even spread of years experience as an “architect”:

How Long

Career Progression

We asked what people had done before they became an architect and what they think they’d like to do next.  As you can see, software development is a common starting point (I notice we didn’t get any Infrastructure Architects responding) with Enterprise Architecture looking like the most popular next destination:

Career Path 2

Effectiveness

I’m extremely pleased no-one felt categorically ineffective, but then there wasn’t exactly an over abundance of confidence either: half of our respondents answered “yes” whilst the others said (typically for architects) “It depends”:

Effective

Selected Comments

In closing, here’s a selection of comments we received to the more open-ended questions:

What is your biggest challenge as an architect?

“Inter-Personal communication, especially when doing Enterprise level work dealing with application level architects.  Some cannot see the forest from the trees and want to re-litigate the “what” (strategy aspects) instead of focusing on the “how” (how to make it work to achieve the what outcomes).”

“Understanding the role within the political landscape, and being able to effectively convey this role to business and it people who don’t understand/value the role of an Architect.”

What do you feel makes you effective / ineffective as an architect?

“I think of myself effective when I align architecture with the business strategy and maturity. Not the best architecture, but the best fit architecture for an organisation at their particular maturity, budget and strategy level make me an effective architect.”

“Effective with a balance of inter-personal skills and technical abilities.”

What advice would you give to new / aspiring architects?

“Focus on the outcomes and what constitute success for the business, not so much the process of architecture (standards, practices, the next best thing), but more the product of architecture (alignment, value, outcomes).”

“Use Rozanski and Woods.”

How Not to Screw Up an RFP Response

Originaly posted by AdrianK, 26-Jan-2010 at:

Vendors typically have to expend a huge amount of effort when responding to an RFP.  This article looks at how they can help themselves (and thus the client), so that the effort isn’t wasted.  The short answer is that whist RFP respondents typically focus on the solution they are offering, the real key is to take the human factors of the reviewers into consideration.

In my role as a Solution Architect (or perhaps just by being one of few resident development skilled geeks) I contribute to the RFP process – on the client side.  I’ve also done a wee bit on the vendor side too.

Having done a string of RFP reviews in recent times I feel compelled to provide some feedback to those of you out there who submit RFP responses; and whilst most of you are doing well there are others who (with all due respect) desperately need some help.

[A bit of context – this feedback is based on experiences within the New Zealand public sector.  I can’t vouch for other countries but I’m sure a lot of these points are transferable].

Before I lead us through the vast litany of unfortunately very common mistakes, let me give you some insights into the life of a RFP reviewer so that you can understand the context in things happen.

RFP’s are generally structured into sections with specific statements and questions within each; for the review, reviewers will be given a pre-defined score sheet from the contracts team (who usually oversee issuing of the RFP), and it’s no mistake that the score sheet utterly reflects the RFP.

Some score sheets expect the reviewer to individually score each answer and question pair; others expect a single score per section of questions. 

When I’m reviewing responses that require score by section, I generally work through each section in turn for all responses, in other words I work by section not by response.  For example, for a recent RFP review I was reviewing a stack of hardcopy responses:

  1. I usually start with a very brief flick-through of all the responses to get a feel for what’s coming.  The score sheets are usually in Excel all setup with the respondents entered and formulas ready to aggregate results on a separate worksheet (which I avoid looking at until the end of the review).  I stack the responses in the same order they are in score sheet.
  2. I’ll review the RFP itself again, as well as the question and answer sets that have been created – and I’ll have full print-outs of each at hand.
  3. I’ll then start the review proper, starting with the first appropriate section and the first response, then moving on to the next response.
  4. Once I’ve scored all responses for the current section I’ll move on to the next.
  5. If a section to be reviewed is large or covers multiple topics (they aren’t always as cleanly segregated as you might want) I’ll setup a more granular sub-score sheet of my own somewhere; in this case I might start reviewing responses per individual question, but not always.

Additional notes for each score are also entered; these are pretty essential for the final group review.  As you might know the RFP’s will be reviewed by a group of people who will then come together to thrash out a result (or a short list).  In a recent case my review took a full week (including normal day to day interruptions) thus the notes are essential.

Once the reviewers have completed their individual reviews (and scoring) they all get together for a formal review and scoring session where the final grading is done – this is the bit that counts.

The crucial point is that reviewing RFP’s is long and tiring work, particularly if there are a lot of responses, and it’s harder with responses that are of a poor quality.  Thus one of the keys to a good result is to take the human factors of the reviewers into consideration – make your response a pleasure for them to score.  So, how do you actually do that…

Structure

If you want best “bang for buck” this is the mistake you can’t afford to make: as mentioned above RFP’s and there score sheets stick to the same structure – deviating from that structure in your response is asking for a serious amount of pain and may well land you in the bottom %60 of scoring.

When you have to review and score a dozen odd responses you don’t have time to hold peoples hands – if the your response clearly follows the RFP structure the reviewers won’t have to think [1] in order to find the information to review, and they’ll thank you for it.

Use section names and paragraph / question numbers from the RFP to label the content in your response, and include this in the table of content if appropriate: make sure it’s really easy to scan, use decent indenting, bolding and other presentation techniques to make it so – but don’t go overboard. 

With most RFP responses, at least some of the respondents will do just that; this consistency makes it easier for reviewers to work with those responses and the more that do this the more they will all benefit from the consistency; correspondingly, failing to do so will put your response comparatively on the back-foot.  This is particularly true the more responses there are.

Next on the priority list is a decent Table of Contents (ToC), and please, please, please don’t forget page numbers.

What you want is a nice, clear, easy to read ToC which matches the RFP structure, with page numbers so I can jump straight there.  “Hand-Over”?  Oh look its on page 28.  “Security Testing”?  Page 13, bingo.

RFP’s that do none of this are so awful to review it’s not funny, and it takes little imagination to guess how that impacts on scoring, after all you can’t score a response you can’t find.

I’ve seen everything in between: responses with no ToC, ToC but no page numbers (bizarre) and page numbers but not ToC (near pointless).  The sad truth is that whilst the reviewer should be scoring you on you content, you’ll get scored on your delivery instead – if it’s poor. 

This brings up an interesting point, in that (for the reviewer) there’s often a fine line between scoring the response and scoring the way it’s delivered, and the division between the two can get quite murky at times.

Finally, RFP reviews always include a section for presentation and delivery; these should be easy points to win if you follow some of the advice above.

Content Quality

By this I don’t mean that you offer a database that is redder than everyone else (a red database is fastest, yes?); what I mean is that your response must answer the questions that have actually been asked.  You might think this was obvious, however, I regret to inform you that the obvious is obviously not that obvious.

Failing to actually answer the question is at least as dangerous as ignoring the RFP’s structure.  First tip: actually read the question.  Read it again and make sure you understand it.  Count to ten before you start writing.  Discuss it with a peer.

It’s tempting to respond to the “training” section of questions with your standard training blurb – don’t rely on this.  Make sure you understand the specifics of what is being asked and directly answer it – make it as easy as possible for those poor tired reviewers to give you full marks.

Responses that (reading between the lines) suggest the respondent is capable – but which don’t directly answer the exact stated question put the reviewers in a tricky position. 

If in doubt answer the question directly (‘what they asked – not what they meant”, as strange as it might sometimes appear) and then additionally provide a ‘second’ answer that answers “what they meant not what they asked”.

In short: make sure you directly and specifically answer all the mandatory questions in the RFP.  Reviewers generally mark a score as set-out in a predetermined score card (most likely defined by the internal contracts team); one of these options will cover responses that fail to answer questions specifically.  Often questions can be lumped together into section and a score is given for the section as a whole – if you don’t answer all the mandatory questions you risk being thrown into the ‘failed to provide a response’ category even if you did answer some of the questions.

Consider very carefully when asked to describe your approach to completing a specific deliverable; is the RFP trying to elicit the steps you go through or your thinking behind those steps?  It is – trust me.  Knowing what your process is can be illuminating (but not always in the right way) where-as getting an understanding of why you do it that way is often more helpful – it shows that you can justify your approach or might suggest that (due to your understanding) you can compensate when variations occur.

“All software we produce under goes our comprehensive range of time-proven of software testing techniques” is not going to score you anything.

“All software component testing is automated using N-Unit with code coverage of at least %80 by the end of every sprint.”  Is much better – I know the tools you use, it looks like you know what you’re talking about (code coverage) and your testing is integrated with your development methodology (don’t tell me you’re “agile” elsewhere in the response and then fail to mention relevant agile practices where appropriate).

Content Quantity

Reviewers will be looking to get the review done as fast as possible – be as succinct as possible – both in volume of text and presentation.  The average reviewer may not be too interested in a whole page executive summary

(although this kind of thing may be useful to others?).  Also, the bigger the document is the harder it will be for reviewers to find information if it’s not blatantly obvious from the table of contents.

The balance between too much info and too little can be a very delicate one, and it’s easy to get wrong.  One approach that might work for you is to provide some level of detail (to try and expose your depth of knowledge) but not for the whole breadth of the issue

Pick you targets; make sure you understand the RFP and your relative strengths and weaknesses, what responses are you giving elsewhere?  Some questions will lend themselves to a longer answer better than others, and for others a shorter answer.

If the RFP simply states that you need to confirm acceptance or acknowledge something then do so (assuming you accept, of course); something like “We confirm acceptance of this requirement” should do the trick.  Evaluate the question – don’t feel you need to give additional info if it’s not necessary. 

If you add additional information please make sure you still formally state acceptance as a clear acceptance is the fastest way to full marks. 

Starting with the acceptance and then providing additional info is probably best.  One advantage of sticking to the acceptance statement only is that it means you can add more content elsewhere; save yourself for where it’s worth going the extra distance, so that the overall response isn’t bloated.

Name drop – Mentioning the names of specific processes and technologies can be a very useful way of conveying a sense of depth without going into detail, for example: when questioned about security testing name-dropping specific threats demonstrates a knowledge of the domain – “… protection against SQL Injection, XSS, and Drive-by attacks…” makes it sound like you know what some of the potential and specific threats are, where-as simply saying you’ll defend against malware is very vague.  Of course anyone can name-drop things they don’t actually know anything about, but the rest of their answer (and the way it is written) should give an indication as to the overall authenticity of their knowledge (as will the response overall).

Name-dropping is also useful in that anyone scanning a page of text might recognise words which catch their interest – and so lead them to actually read your response more closely.  Conversely – a lack of ‘buzz-words’ might imply that you’re merely waffling.

Conversely, be careful not to rely on name-dropping alone; there are definitely circumstances where it’s worth putting a small degree of appropriate fluff around things; and also along these lines it’s a good idea to provide the full name rather than the acronym only.  For example, when listing relative experience:

  • Wrong:  SOA
  • Good:   Service Orientated Architecture (SOA), 5 years experience.

Don’t wax lyrical about the subject if it’s not directly answering the question, for example: don’t discuss the advantages of standards compliance if the actual question is to simply state how you actually ensure the standards are met.

Presentation

Have you ever been guilty of judging a book by its cover?  Presentation counts – and done right it’s easy an ‘easy’ way to earn points.

There are a number of points to this: the obvious visual and aesthetic aspects and (the less flashy but just as important) usability aspects like layout and wording.

An optional but useful technique is to prefix your individual responses with the actual question from the RFP, this leaves the reviewer in no doubt they have found the right content.  A clearly headed and structure response should negate the need for this – so it does depend on how you want to present your response.  It can also help whoever is writing the response to stay focused on target. 

If you have supplementary information in other parts of the document mention it clearly at the end of the ‘formal’ part of the response to a specific question.  Supplementary info is good but may not always be read in full by all reviewers:

  1. Reviewers will focus on the formal responses first and they may not review supplementary content particularly if they are under time pressures, tired or feel overwhelmed.
  2. If the reviewer thinks they have formed a sufficient opinion based on the ‘formal’ answer to a question they are unlikely go looking for additional info.

Including additional sections of information is fine – just make sure it doesn’t get in the way; reviewers hate having to wade through a big thick document just to find the information they need.

Never attach core information separately to the response (“sample widgets attached as jpegs”), if it’s worth including in the response please embed it in the actual response, and ensure it looks crisp when printed / photocopied in black and white (because not everyone will print in colour).

One approach is to include a “lesser” (but usable/readable) example in the RFP response document and a big flash high-res copy as an attachment – if the lesser example wets the reviewers appetite they’ll be more likely to go to the trouble to look at the separate attachments.

Think about who will be reviewing the responses: it will be a range of people with various skills and knowledge; what they will all have in common is (probably) a lack of time, tiredness and a lot of responses to go through – make it easy for them.

A lot of companies have pre-defined templates for making pitches, and some of these appear to be used for RFP responses; by all means use these as checklists or something to spark though on the response – but don’t use the template for the response: it probably won’t relate to the structure of the RFP, and will attract the pitfalls mentioned above.  In addition, a response whose structure bears little resemblance to the RFP makes it look like you haven’t even read the RFP – a sure-fire way to get the lowest score (or risk getting thrown out altogether).

Website focused RFPs’ will typically have requirements around the aesthetic needs of the website; don’t provide text only answers – visuals are a must.  Be pedantic over how these are displayed – they must be high quality (Nothing beats a quality full colour reproduction of a nice visual).  Think about how the RFP is going to be actually delivered (usually a combination of both hard and soft copies).

When binding the response make sure it’s easy to turn the pages and that all the content on the page is clearly visible.  Responses that sit fully open on any given page are a blessing – ones that refuse to sit still without folding over are painful.  Ring binding is good, avoid staples and paper clips.

At the end of the day – if the RFP calls for a solution with any sort of aesthetics you don’t want a poorly presented response; if your response looks mediocre it won’t give the impression you can deliver a ‘killer’ design.

Thinking Ahead

RFP responses are usually reviewed by a group of people – usually selected to provide a range of stakeholders and expertise.  You’ll have business focused reviewers (perhaps end users of the system) as well as reviewers who are there mainly for the technical aspects.  These different audiences may or may not have the same degree of sway within specific areas of the review. 

One thing to consider (for example) is the kind of language used to answer a certain question, for example: answers that require a technical response will probably require a different language style than answers that deal with more empirical subjects like visual design and user engagement.  Think about the kinds of people who will be reviewing your response – and not just the response as a whole but also those that might focus on a specific area (technology, business, project management, and so on). 

Get your geeks to write the technical content, chances are the reviewers will rely on the geek reviewer to help guide them during the final review session where the final scores are thrashed out.  The same applies to other sections of the response – get the most relevant person (like the appropriate Subject Matter Expert (SME)) to write the content for a given area; get others to review and critque their work but becareful not to stamp all over their style and approach too much if it’s likely to appeal to the corresponding SME on the clients side.

Staff / Resourcing / People

One of the sections you’ll find in a typical RFP is one that requires you to provide information on the staff who’ll be working on the project, and you’ll usually be asked to explicitly state staff members by name against specific roles.  This will be mandatory – so make sure you do it.

Make sure you answer the question – kind of obvious; don’t just rattle off the standard blurb (unless it’s fit for purpose) – it’s easy to slip into making the mistake of covering someone’s past history even if it’s not directly applicable.  Make sure you directly and clearly answer the specifics of the question before adding details about what you do in your spare time.

Typically you’ll be asked to provide relevant details as to the experience of these people, perhaps in the form of a one page CV, there are many pitfalls here to be wary of – including all the baggage that usually goes with good CV writing, but there are several simple things you must do to avoid a bad review:

  1. At the very least: state the number of years experience in the relative field.  Stating the number of years the person has worked for your company is pretty much irrelevant – say that if you want to, but only in addition to their total relevant experience.
  2. Stating relevant skills, projects, technologies and so on is good but not enough on its own (see the ‘name dropping’ section, above).  Please don’t provide three pages of waffle and not state the total number of years of relevant experience.
  3. Provide all Staff CV’s / Bio’s in the same format.
  4. Pictures aren’t mandatory but are generally a good idea – people like seeing people.  Make sure the photo quality and reproduction are excellent otherwise the value of having the photos will be diminished or may backfire completely.

RFP requests are typically after a well rounded solution (for example, if its a website there will probably be business, aesthetic, architectural, development and testing aspects that need addressing), bear this in mind when providing staff bio’s.  I’ve reviewed RFP’s that needed a breadth of skill, and seen responses that listed a bunch of developers or designers and little else. 

Don’t be afraid of out-sourcing.  As a general rule I’ll give more points to a response that out-sources security testing to a specialist [2] firm rather than one that does it in-house, although this can depend on the size and skill of the vendor behind the response.  That’s my personal position, and not everyone has the same views as me.

I guess there’s the potential for that to backfire if the owner of the RFP has some pre-conceived idea that they want a single vendor to deal with.  If you’re a small firm then I’d say you’re better off taking the out-scouring route, and you can always have them working for you as a sub-contractor – so there’s still only one point of contact (and invoice) for the project owner to worry about.  Just make sure you’re clear in your response.

In Conclusion

Writing a good RFP response is learnt skill and it’s evident when the response is coming in from someone who has done it before, but you have to start somewhere.  It’ll be your team that does the actual work if you win – so you’ll stand the best chance of winning if the team contributes to the response.  Allow yourself plenty of time, check the basics – and go get ‘em!

References

http://en.wikipedia.org/wiki/Don’t_Make_Me_Think1. http://www.morphological.geek.nz/blogs/viewpost/Peruse+Muse+Infuse/The+Laws+of+Specialisation.aspx2.

Some rights reserved.  http://creativecommons.org/licenses/by-nc-sa/3.0

Converting Waterfall Requirements into Underground Agile Features

(Originaly posted by AdrianK, 20-Sep-2010 at: http://www.morphological.geek.nz/blogs/viewpost/Peruse Muse Infuse/Converting Waterfall Requirements into Underground Agile Features.aspx)

Converting Waterfall Requirements into Underground Agile Features

Well here’s an interesting thing: we’re doing a decent sized project using a standard sort of requirements driven approach in a spreadsheet in a government agency which has mixed feelings about agile – and guess what?
Well, thanks to some discussion, people who aren’t afraid to try new things and luck, we’ve managed to start taking an approach which might be known to some of you as a word that starts with the letter “A”.

Those “in the know” know what we’re up to – because they’re the ones doing it – most other people are blissfully unaware. For those of you unfamiliar with this hugely successful approach it’s called “Agile Undercover“. One of the biggest barriers to successful agile adoption is the weight and baggage currently associated with the agile buzzwords – as soon as you say agile it instantly becomes political and messy: cowboys use it as an excuse to do “iterations” and the naysayers bring out their pitchforks; and no one listens to the poor folks in the middle who actually know what they’re talking about. This might not be the case everywhere but I doubt it’s hard to imagine.

Agile undercover is where the purists go back to basics. If you really want to “do agile” then what you’re really saying is “I want to do the important things” – this means honouring the principles and probably implementing some of the practices; the one thing we can leave behind are the buzzwords.

Real-Life War Story

Some quick context: the core internal project team includes a Project Manager (PM), Business Analyst (BA), Manager of the Web Team and me as the Solution Architect; all development will be done by a vendor – we don’t have any developers in-house so this won’t be your typical developer driven uprising.

So, here’s what happened. A friend of mine who heads up the Project Managers is keen to look into agile with some degree of seriousness; in fact he recently did a “lunchbox” session on agile – skipping most of the buzzwords but including concepts like “features”. He’s mostly coming at this from his own angle – I wouldn’t describe him as a long-time SCRUM practitioner or anything – so good on him.

“Our” PM was at the session; she’s never done agile before in her life – but she’s open to new ideas and always keen to learn new things. Awesome. The rest of the core team were in a similar position – not adverse to the idea. Timing is everything; I need to explain the point we were at in the project. There’d been a massive requirements gathering effort, after removing duplicates we managed to get down to 196 “Business Requirements”, these had then been prioritised by the wider internal project team.

The next step was to confirm to our vendor what we wanted included in the first delivery so they could estimate effort and cost for us. No problem there except going into this we had no idea what the total effort would be – would we be including too much or too little?

I suggested a SCRUM based approach – but I didn’t quite put it like that; this suggested approach was one I’d suggested earlier – probably with a view that it’d take people time to get used to the idea. This aligned nicely with our PM discussing some concerns about how the requirements and estimation process was likely to shakedown – not concerns with the vendor or any people involved – purely the process.

My suggestion was simple – let’s rank all the requirements (in terms of business value) and then get the vendor to score all of them for effort giving us a rough total cost and date. The PM (who attended the lunchbox session) wanted to group requirements into logical “features” (her words not mine). “Bring it on” I said. Boy do I have a plan for you! First we took the existing spreadsheet of requirements which looks something like
this:

The key point here is that we have 196 requirements that are broadly prioritised (90 were “critical”), we also have a column that states whether the requirement can be met Out-Of-The-Box (OOTB), requires configuration or needs custom development (this isn’t the same as an actual score for effort – but it’s a good start; if something’s OOTB then there’s not much point arguing about it regarding timescales). I then made a copy of this worksheet and fiddled with the layout until I got something that would resemble a
Story Card.

The idea is that there’s one requirement per row, and if you format it appropriately you can print one requirement per page, all you need to do then I print four pages per sheet of paper and take to them with scissors or a guillotine. The original list of requirements had a “category” column which broke the requirements into 5 or 6 categories –
they were a bit broad but helped us break the next part of the process up.

We spread all the requirements for a given category out on the table and started sorting them into logical features – things which sounded the same or would naturally fit together, things which would naturally make a unit of work. We at this stage we treated all requirements as equal – ignoring the existing priority rankings (“Critical”, “Highly
Desirable” etc). Naturally this process led to some great discussion.

Some points that came out:

  1. Don’t worry if a feature pile gets to big – until it’s scored you just don’t know, and it’ll be easy enough to break that feature into smaller parts later (did someone say iterations? Naughty! – this is undercover, remember?).
  2. Some requirements seemed better suited to feature piles from the other “legacy” categories – no worries, just add / remove them from piles as required.
  3. By flicking through a feature pile you can easily get a feel for how important it is as the existing
    requirement level priorities were plainly visible (the big red line means “Critical”).
    We needed to easily identify feature piles, so we started labelling them with a sticky note.

Pretty soon we ended up with feature piles, which we grouped by our “legacy” categories, and roughly ranked for good measure.

The final act in this immediate process was to rank all the feature piles (in terms of business value), relative to each other. At this point we numbered all the piles: 1 (most important) down to 39 (least important); that’s an average of 5 requirements per pile.

After that it was a simple matter of adding a new column to the spreadsheet thus capturing the results.

We offered our proud piles to the vendor but they chose to take the digital copy; I think that’s actually the best idea: we safeguard the “originals” and the vendor can print their own copy of the requirement cards – including any additional columns they want to use.

Next Steps

The requirements now need to be scored for effort by the implementation team (our vendor), and rather than ask them to score each feature pile for effort we’ve asked them to score each requirement – why? I hear you ask. The problem with scoring only the feature piles is that if for any reason we have to split a feature pile up we
won’t know the effort for each. The best we can do is to have a score for each requirement and thus get a score per feature pile – assuming we need to start breaking them up.

Naturally the implementers will be concerned with managing dependencies; so how best to score for effort? I know from experience that you want to score realistically but take advantage of anything you can – therein lies the danger: if they score a particular requirements effort as low based on a dependant requirement already being implemented we’ll all run into problems if we start changing the contents of the feature piles.

This is where simple common sense comes into play: the feature piles represent our current thinking as to how they should be implemented – so things are only going to change for a good reason. The build team should be able to use this knowledge to their advantage – scoring effort based on any advantage via dependencies is fine
(it helps the bottom line) but they need to let us know; likewise we need to discuss with them any changes we’re thinking of making to the feature piles.

Now we get to the second part of the pep talk I had with our PM: once we have a ranking for business value and a score for effort we can start to look at how we “phase” the work for implementation – big bang or chunks. The one (of many?) rules I suggested putting in place was that regardless of how long a “phase” is we identify scope for that and not change it once that phase starts; the time-box for the phase must not change. 

My reasoning for the fixed phase length (yes – iteration if you will) is based on the tried and true Agile practice of being able to establish history – so we get to the point of being able to say “we get through X worth of effort per iteration”, therefore we know how long the project will take overall, or how much we can do for a fixed cost. So, we’re all looking forward to see how the effort scoring goes.

Key Takeaways

  1. Avoiding Agile buzzwords helped avoid political minefields and allowed everyone (regardless of agile experience) to get involved in the process and contribute to it.
  2. Working with requirements in a tactile fashion is easily the fastest way to deal with them; there’s no bottleneck of people fighting over the mouse and working this way is very liberating.
  3. You get a good overview of the entire projects scale.

RoboMojo

RoboMojo

RoboMojo is simply a shell for calling Microsofts robust file transfer tool: ROBOCOPY.  You can get it (either the program itself in a stand alone MSI installer, or the source code) from http://robomojo.codeplex.com.

RoboMojo let’s you set-up “Tasks” that you can get ROBOCOPY to do – avoiding the need to enter complex arguments everytime (and get them wrong – after all, to err is human).

With RoboMojo you can also set-up “Jobs” which are collections of tasks.


Before You Start

RoboMojo uses settings configured in the RoboMojo.config file.  The three settings to verfiy are:

  • Morphological.RoboMojo.XmlDataProvider.NameAndPathOfDataFile – specifies where your RoboMojo Jobs and tasks are saved.
  • Morphological.RoboMojo.XmlDataProvider.PathOfDataFileBackups – specifies where back-ups of your RoboMojo Jobs and tasks are saved.
  • Morphological.RoboMojo.TaskExecutorMSRoboCopy.LocationOfRoboCopyEXE – specifies where the ROBOCOPY.EXE file is on your system.  The default setting should work for most users.

Using RoboMojo

RoboMojo has one main screen, with three tabs.

  • Run: used to run Tasks or Jobs
  • Edit: used to manage your RoboMojo Jobs and Tasks
  • Options / About: self explainatory

The RoboMojo Jobs and Tasks you create are stored by RoboMojo, currently the only option for this is as a text file.  It’s called RoboMojoState.txt, and by default is kept in the RoboMojo folder.

Shortcut for Copying RoboMojo Tasks

On the Edit tab, drag an existing Task onto a Job in the main tree control, this will create a copy of that Task on the target Job.  The “Edit Task” part of the UI will populate with the details of the Task – beware that the new Task needs to be saved before selecting a different Task or Job.
Issues / Things to be Aware of

You can change the “theme” of RoboMojo on the Options tab, but the theme only applies to the main window, and it won’t persist if you close RoboMojo.  This feature will be completed in a future release.

The XML Data Provider likes to make a back-up copy of the RoboMojo data file (RoboMojoState.txt) wheneever you make a change.

All RoboMojo Tasks have a “TaskOrder” property; at the moment you can’t edit this via the UI – you’ll have to dive into the RoboMojoState.txt file and change it manually.
Using ROBOCOPY

Beware of calling ROBOCOPY tasks that write to special areas of the file system (like “Program Files” in Windows7) – if ROBOCOPY fails the ROBOCOPY cmd window will disappear realy fast (before you can read the error message.  The best way to deal with this is to get ROBOCOPY to write a log – this is one of the many options you can give to ROBOCOPY.

See the “Robocopy Options.txt” for more info, or manually invoke ROBOCOPY from a cmd prompt with the argument /?  I’ve also found this very useful PDF (http://theether.net/download/Microsoft/Utilities/robocopy.pdf).
Licence Stuff

  • RoboMojo is free and open source software (but not the ROBOCOPY.EXE itself which belongs to Microsoft) and is released under the Ms-RL.
  • The icon used is by Forrest Walter (www.forrestwalter.com/icons).
  • The full licence is provided in Licence.txt.  Contributions welcome, for more info see: http://robomojo.codeplex.com

5-Layer Architecture

5-Layer Architecture

This is the homepage for what I’m calling the 5-layer Architecture.  The current version is v0.2, posted on 29-Aug-2011, is also the first publicly published version.  My reasons for doing this are (at least partially) covered in the document.

The current PDF is 33 pages long, with some supporting diagrams.  My intention is to expand on this by including code examples, and providing one or two “quick start” / cheat-sheet type reference documents to make it more accessible.

Any feedback is of course warmly encouraged and most welcome; email me at: adriank [at] morphological [dot] geek [dot] nz

Quick Introduction

The 5-Layer Architecture reflects “real-world” work that I have been involved with since around 2003.  This work is mainly ASP.NET based; so you might also refer to it (if you feel so bold) as a “Classic ASP.NET Architecture” – classic in the sense that it seeks to describe architectural work I have seen repreated in many solutions over the last few years, and work I have seen discussed in articles and blog posts on the net for some time.

So I’m not claiming anything particularly “new” here; what I am claiming is a “bundling-up” and formal description of architectures I have seen and agree with, specifically including rules and principles that will help designers and developers make informed decisions.

It’s my hope that this work will be of particular use to developers new to architecture or considering moving into architecture more fully.

The 5-Layer Architecture is primarily concerned with the logical and physical partitioning of code into packages which support reuse.

As you can see from the diagram below, it partitions the system into (surprise!) 5 Layers.  Unlike a lot of other architectures that focus on the “main horizontal” layers (like the UI, BL and DAL) the 5-Layer Architecture formally recognises other parts as a logical layer that deserves equal recognition.  Please read the formal description (link above) for a full and proper introduction.

Logical Layers and Key Components

Logical Layers and Key Components

Morphfolia Tutorial: the ‘Bare Bones’ PageLayout

Morphfolia Tutorial: the ‘Bare Bones’ PageLayout

PageLayouts are a key extension point for Morphfolia; in this article we’ll introduce how to build a PageLayout by looking at the absolute bare minimum you have to do to get one un and running, line by line. The Morphological.Kudos project (part of the standard Morphfolia relase) is a library of PageLayouts, it serves both as an SDK and it is actually used ‘in production’ on morphological.geek.nz. My only regret with the current release of Kudos (v2.4.1.0) is that some of the code is a bit old and hasn’t been refactored to a high degree of polish; it certainly works – but it’s not as clear and clean as it could be. If you want the ‘definative’ guide to build PageLayouts then this article is the place to start.

First, we have the using statements and namespace declaration – nothing terribly complex about that. You can namespace your layouts anyway you like, but it is a good idea to think about this carefully in advance – any subsequent refactoring of the namespace will affect users who are actively using the PageLayout.

using System.Web.UI;
using System.Web.UI.WebControls;
using Morphfolia.Common.BaseClasses;
using Morphfolia.Common.Info;
using Morphfolia.PageLayoutAndSkinAssistant;
using Morphfolia.PageLayoutAndSkinAssistant.Attributes;

namespace Morphological.Kudos.Layouts
{

the class declaration is fairly standard, but there are a couple of things you need to do:

  1. Decorate the class with IsLayoutWebControl attribute (found in the Morphfolia.PageLayoutAndSkinAssistant.Attributes namespace).
  2. Inherit from Morphfolia.Common.BaseClasses.BasePageLayout
  3. Finally, its good practice when developing WebControls to include the System.Web.UI.INamingContainer interface.

Stricly speaking we don’t need to worry about INamingContainer as this PageLayout isn’t going to be functional (it won’t hold controls that need to do PostBacks, etc). Generally speaking the PageLayouts are used as templates for serving content not applications – but they can.

Decorating the class with IsLayoutWebControl means that the PageLayout will be available to users when adding and editing pages.

[IsLayoutWebControl]
public class BareBones : BasePageLayout, INamingContainer
{

This ‘BareBones’ example is going to be very basic; we’ll display the page title and content, only. In order to implement this we’ll declare a couple of controls to display the information – a Literal into which we’ll put the page title (formatted as a heading), and a Panel to hold whatever content is assigned to the page. Obviously you can put whatever you want in here – the specific controls used are relevant only to your PageLayout and aren’t required specifically to get the PageLayout working.

private Literal pageTitle;
private Panel contentPanel;

This next property is required by the base class (BasePageLayout). It allows callers to pass in WebControls for inclusion in the PageLayout, for example a site map, search results or tag-cloud. How you implement the property is up to you, but this is what I would normally do.

private Morphfolia.Common.WebControlCollection childControls;
public override Morphfolia.Common.WebControlCollection ChildControls
{
    get{
        EnsureChildControls();
        if( childControls == null )
        {
            childControls = new Morphfolia.Common.WebControlCollection();
        }
        return childControls;
    }
    set{
        childControls = value;
    }
}

Next we have the contructors: the standard arguement-less one, and one that can take a WebControl. You can dispense with the constructors if you wish, although you will need them both if you want to pass a WebControl straight in.

public BareBones()
{
}

public BareBones( WebControl childWebControl )
{
    ChildControls.Add( childWebControl );
}

One of the main reasons the PageLayouts exist is to support custom-properties – to enable end-users to be able to configure their pages how they want them. Here’s an example CustomProperty – in this case it allows users to set a width, which will control how wide the content is.

Currently the admin UI allows any text-based input, however, you can type custom-properties any way you like – all you need to do is validate the user input (which we’ll cover soon).

A CustomProperty is any ‘normal’ class property that is decorated with the IsCustomProperty attribute, it can be called whatever you like (subject to normal language restrictions). In addition to the IsCustomProperty attribute are several other attributes that provide metadata to the system, which drives the UI provided to the user when they work with the PageLayout whilst setting up a page.

What these additional attributes are, and what they do, should be self evident. All the attributes you see here take a string arguement, which is simply the value you want to assign (e.g: PropertyFriendlyName = “Content Width”). The Morphfolia.PageLayoutAndSkinAssistant.Attributes namespace provides a couple of classes (such as SuggestedUsageNotes and Descriptions) which contain pre-defined messages for some of the CustomProperties commonly used.

I’ve used plain text in this example, but you’re better off defining some constant values for consistency, especially if you’re going to develop a comprehensive PageLayout library.

private Unit overalWidth = Unit.Pixel(650);
[IsCustomProperty,
PropertyFriendlyName("Content Width"),
PropertyDescription("Use this property to set the width of the content area."),
PropertySuggestedUsage("Fixed width in pixels (e.g: 220px) or a percentage (e.g: 50%).")]
public Unit OveralWidth
{
    get{ return overalWidth; }
    set{ overalWidth = value; }
}

Defining content-containers (places for the user to assign content to the page) is pretty much identical to custom-properties: a ‘normal’ property decorated with the appropriate attributes, and it can be called whatever you like (subject to normal language restrictions). There are three attributes you can use, but only IsContentContainer is required. ContentContainerDescription allows you to describe what the content container is for (main content, navigation, footer, and so on) and ContentContainerColour allows you to color code the content containers – useful if you have a few. When the content container is displayed in the edit page UI (for users to assign content) the background of the content container is colored as per this setting (otherwise it’s a pale blue).

private string userContent = " ";
[IsContentContainer,
ContentContainerDescription("Main page content."),
ContentContainerColour("#ddeeff")]
public string UserContent
{
    get{ return userContent; }
    set{ userContent = value; }
}

If you provide a ‘Current Layout Icon’ you can indicate to the user what the selected PageLayout will look like and give visual clues as to how the content will be layed out; this icon is simply an 100 pixel square JPG which is optional – but strongly recommended. Here are some example PageLayout icons. The name of the file is based on the full type name and assembly name, syntax: “[type name], [assembly name].jpg” e.g: “Morphological.Kudos.Layouts.QuadPageLayout, Morphological.Kudos.jpg”

A simple PageLayout implemented as a 3 column table.
A PageLayout consisting of a table with 2 rows and 2 columns.
The PageLayout for a Blog: it has one content container that sits under the main blog area.
A space for content under a picture with properties.
A table with 10 content areas, all color coded for ease of content assignment in the admin section.

The FormTemplatePresenterType property defines the FormTemplate provider to be used by the PageLayout. This property is not required by the PageLayout base class but it is needed if you want to display FormTemplate structured content.

FormTemplate providers deserve documentation of their own (which will be forth coming), in a nutshell: FormTemplate Providers allow you to display structured data – as formatted by the provider, this is useful for lists or collections of things. I use a FormTemplate Provider to render items on my Product Backlog.  Normally content is input and stored as raw HTML (via the WYSIWYG editor), but you can also input structured content via a form; the user input form is generated automatically based on a simple XML file – you can have as many of these as you like.  All the XML file has to do is confrom to the simple FormTemplate schema.

When a user enters content via a FormTemplate the resulting is content is stored as XML; then when the page is served it is presented (i.e: formatted) via the specified FormTemplate Provider rather than being simply inserted into the output stream as raw HTML.

private string formTemplatePresenterType 
    = "Morphological.Kudos.FormTemplatePresenters.LivewireProblem, Morphological.Kudos";
public override string FormTemplatePresenterType
{
  get
  {
      return formTemplatePresenterType;
  }
  set
  {
      formTemplatePresenterType = value;
  }
}

Anyone who has built WebControls will be familiar with the CreateChildControls method – it’s where the majority of the WebControl is usually constructed. We don’t have to do anything specific here as far as a PageLayout is concerned, but it is the best place to start constructing the WebControl. As you can see – this example doesn’t require much work, we just need to instatiate a Literal for the page title and a Panel for the content.

protected override void CreateChildControls()
{
    pageTitle = new Literal();
    Controls.Add( pageTitle );

    contentPanel = new Panel();
    Controls.Add( contentPanel );
}

InitializeContent is a method we have to implement for a PageLayout to work, it’s where the PageLayout receives the content to be displayed and inserts it into the correct place in the PageLayout. In this example the PageLayout has only one content container so teh work we do here is fairly trivial, however, you could have multiple content containers to assign content to and you could also incorporate additional logic regarding the location and presentation of it if you wanted to.

public override void InitializeContent()
{
    EnsureChildControls();

    string propertyType;
    int temp;

    if (CustomProperties != null)
    {
        for (int i = 0; i < CustomProperties.Count; i++)
        {
            propertyType = CustomProperties[i].PropertyType.PropertyTypeIdentifier;

            if (propertyType.Equals(
    Morphfolia.Common.ControlPropertyTypeConstants.PropertyTypeIdentifiers.CONT))
            {
                temp = GetContentInfoIndexById(int.Parse(CustomProperties[i].PropertyValue));
                if (temp != Morphfolia.Common.Constants.SystemTypeValues.NullInt)
                {
                    AddContentToContentContainer(tdContentContainer,
                        Page.ContentItems[temp].ContentEntryFilter,
                        Page.ContentItems[temp].Content);
                }
            }
        }
    }
}

Let’s review the important statements. EnsureChildControls() ensures that the CreateChildControls method has been called. In this implementation we are going to insert content into the anticipated control structure of the PageLayout – if it’s not there the process will fail. You could use the InitializeContent method to get the content only – and not affect the control structure then you don’t need to call EnsureChildControls, but you’ll need to do this eventually and this is generally the right place to do it.

if (CustomProperties != null) simply ensures that we have some information worth continuing with.

propertyType = CustomProperties[i].PropertyType.PropertyTypeIdentifier; is where we grab the Property Type of the CustomProperty so that we can ensure that only ‘content’ is added; that check is the next line of code – the if statement:

if (propertyType.Equals(Morphfolia.Common.ControlPropertyTypeConstants.PropertyTypeIdentifiers.CONT))

The PropertyTypeIdentifiers class has constants that help keep the types of CustomProperties consistently defined.

All the content for a page is provied as a single collection (a ContentInfoCollection object), the problem is that this content by itself has no knowledge of where in the page it needs to go – because pages and content are loosely-coupled; the way they are coupled is via a collection of CustomProperties which includes not only all the content / content container ‘bindings’ but also all other CustomProperties as well.

The GetContentInfoIndexById method helps us arrange the content for the page correctly. Given the id of a content item (which is stored in the CustomProperty collection items as the PropertyValue property) the GetContentInfoIndexById method will scan the associated content collection (the underlying ContentInfoCollection object) and get the matching content item.

The code temp = GetContentInfoIndexById(int.Parse(CustomProperties[i].PropertyValue)); ensures that the content item was found, as we only want to add content we know should be there. If the result is equal to Morphfolia.Common.Constants.SystemTypeValues.NullInt we know that the content item we were looking for is not present in the ContentInfoCollection – e.g: the ContentInfoCollection and CustomPropertyCollection are out of sync.

Finally we call the AddContentToContentContainer method which performs the actual job of inserting the content where we want it.

AddContentToContentContainer takes three arguements:

  • contentContainer – the control that we want to append the content to.
  • contentEntryFilter – the content entry filter specifies how the content was entered and how it should be presented – see FormTemplates.
  • content – the content to add.

As mentioned earlier, content can be input as raw HTML or via what’s known as a FormTemplate, in which case the content is structered as XML. The AddContentToContentContainer method will append the raw HTML to the target control – or if the content is XML it will use a FormTemplate provider to present the content appropriately and append it to the target control as a WebControl.

The SetCustomProperties method is virtually identical in general purpose to the InitializeContent method – except that it deals with all the CustomProerties that aren’t content bindings.

The private CustomProperties field holds the internally used CustomPropertyInstanceInfoCollection which holds all the CustomProperties passed into the PageLayout. You don’t have to have this field but it’s a convenient way of working with the CustomProperties passed in.

Just as with the InitializeContent method, SetCustomProperties is usually used to accept the CustomPropertyInstanceInfoCollection passed in and use the contained values to ‘configure’ the PageLayout.

The CustomProperties passed in will typically contain values applicable to formatting (widths, colors, alignments and so on) but it can contain pretty much anything you want.

As with the InitializeContent method we call EnsureChildControls to ensure the expected control structure in instansiated.

Once we’ve established that the customProperties are worht working with we get to the heart of the method; first we get hold of the propertyKey and propertyValue. I then typically have a switch statement that evaluates the propertyKey, and for each propertyKey I want to handle I have a branch of code that uses the propertyValue that comes with the propertyKey. In this example I’m only expecting a CustomProperty that sets the ‘OveralWidth’.

All propertyKeys and propertyValues are strings, but I make use of constants for any properties which get common use – to encourage consistencey, hence: Constants.CommonPropertyKeys.OveralWidth.

As the CustomProperties sub-system only deals with strings – but you typcially code aganist specifically typed properties you need to do some validation and conversion; in this example I’m taking a string value which I expect to be able to convert into a unit (to set the ‘OveralWidth’), and if it fails I set a default value – defensive programming.

private CustomPropertyInstanceInfoCollection CustomProperties = null;

public override void SetCustomProperties(
    CustomPropertyInstanceInfoCollection customProperties)
{
    EnsureChildControls();

    CustomProperties = customProperties;
    string propertyKey;
    string propertyValue;

    if (CustomProperties != null)
    {
        for (int i = 0; i < CustomProperties.Count; i++)
        {
            propertyKey = CustomProperties[i].PropertyKey;
            propertyValue = CustomProperties[i].PropertyValue;

            switch (propertyKey)
            {
                case Constants.CommonPropertyKeys.OveralWidth:
                if (!propertyValue.Equals(string.Empty))
                {
                    try
                    {
                        OveralWidth = Unit.Parse(propertyValue);
                    }
                    catch
                    {
                        OveralWidth = Unit.Pixel(650);
                    }
                }
                break;
            }
        }
    }
}

The final step is to implement the RenderContents method, this is where our WebControl / pageLayout is fianlly committed to the output stream. If you want to do any final adjustments – this method is your last chance.

The EnsureChildControls method is called – just in case. We then check the Visible property – no point doing a bunch of work if the WebControl is not going to be visible (this probably won’t matter when serving the WebControl from an HTTP Handler – but it’s good practice as you may decide to use the WebControl elsewhere). You haven’t forgotten, of course, that a Pagelayout is bascially a WebControl, have you.

The ChildControls property is not on the critical path when developing a PageLayout – but it’s very handy. The BasePageLayout class provides the ChildControls property so that callers can add WebControls to the PageLayouts; as an implementer your only real choice is what to do with them. You can ignore them completely if you wish, or far more usefully you can put them somewher in your PageLayout. You could even be ultra clever and write some logic that put different controls in different places – assuming you knew what to expect.

For this example we’re just appending any controls passed in to the sole content container. Real life examples of this property in action are where Morphfolia adds the SiteMap WebControl, Search Results, Tag-Cloud and WordIndexListPresenter WebControls. See the Morphological.Kudos.Layouts.QuadPageLayout PageLayout as another example.

The very last thing we do in this method is commit the WebControl to the output stream, by calling the RenderContents mehtod, however, just before we do that we ‘connect the final set of dots’.

The pageTitle Literal is finally given it’s value: the title of the page (wrapped up in an HTML <H1> element), courtesy of the PageLayouts reference to the current pages’ underlying implementation of the Morphfolia.Common.Interfaces.IPage interface. This is basically an object that gives us access to the basic properties of the ‘page’ (Title, PageID and so on).

Then we set the width of the contentPanel content container to the value stored in the OveralWidth variable. As I hope I made sufficiently clear earlier – we can set the values against the controls (contentPanel.Width = OveralWidth) either here or back in SetCustomProperties where we processed the CustomProperties initially.

protected override void RenderContents(HtmlTextWriter writer)
{
    EnsureChildControls();

    if( Visible )
    {
        if( ChildControls.Count > 0 )
        {
            for(int c = 0; c < ChildControls.Count; c++)
            {
                tdContentContainer.Controls.AddAt(c, ChildControls[c]);
            }
        }

        pageTitle.Text = string.Format("<h1>{0}</h1>", base.Page.Title);

        contentPanel.Width = OveralWidth;

        base.RenderContents (writer);
    }
}

Morphfolia: Integration Options

At a high-level there are about 10 ways you can integrate with Morphfolia; this article gives an overview of these options.  All of the integration options here are possible without having to modify Morphfolia itself (with the exception of configuration).

Here’s a diagram for context (detailed information to follow beneath).  In the center are the main Morphfolia packages and classes that integrators will probably want (or need) to work with – depending on which approach you want to take.  The blue packages and classes on the sides represent code you might write yourself; with association lines showing the main integration relationships.  (Note the word ‘package’ comes from UML – where it refers to a logic group of items, in this article package also often refers to an assembly).

Click image for a full-size copy (1516 x 1292 pixels, 272Kb)

Click image for a full-size copy (1516 x 1292 pixels, 272Kb)

Let’s go through the 10 options in more depth.

(1) Develop your own website (ASP.NET / ASP.NET MVC) and leverage Morphfolias APIs

The basic idea is to use Morphfolia as a base – rather than starting with a new blank ASP.NET Web Application project; however, you can still use a new blank project if that’s easier for your situation and then leverage the Morphfolia packages and classes that are useful to you.

As shown on the diagram, the Publishing System is possibly what you’re after – although you can leverage pretty much anything (Business Logic, WebControls, Data Access and so on).

(2) Use the Web.Config to route requests to your HttpHandlers, which can also leverage Morpfolia APIs

A lot of flexibility comes from the web.config: direct Http Requests to the mechanism best suited to handling them: could be Microsofts out-of-the-box ASP.NET WebForm handler (System.Web.UI.PageHandlerFactory), Morphfolia’s default HttpHandler or one you’ve developed yourself.

Your HttpHandler can then leverage various packages and classes in Morphfolia.  As per the diagram you’ll probably want to use the Publishing System but there’s nothing stopping you using the Business Logic (Http Logging, the CustomPropertyHelper, etc) and other packages.

(3) WebForms (and other things) can use the WebFormHelper

The WebFormHelper was specifically designed to work with WebForms, but may also be useful with any MasterPages and UserControls that you write yourself.  For more info on how you use the WebFormHelper with WebForms see: Using in an ASP.NET WebForm.

In essence the WebFormHelper can be used in “code behind” and “in-line” as per options 4 and 5 below, the thing that makes it worthy as an integration option in it’s own right is that it’s specifically designed for use with WebForms – allowing you to easily perform common Morphfolia / WebForm integration tasks.

(4) Your MasterPage, WebForm or UserControl views call functionality using in-line code

For example, here’s an example of using the WebForm helper “inline” in a .aspx page which uses a master page; you could do the same thing in the MasterPage itself, or a UserControl.  Just be careful where you call the HttpLogger (don’t call it more than once per pageload).

<%@Page 
Language=”C#” 
MasterPageFile=”~/SimpleTemplatingTestMasterPage.master”
AutoEventWireup=”true”
CodeFile=”SimpleTemplatingTestWebForm.aspx.cs”
Inherits=”SimpleTemplatingTestWebForm”
Title=”Untitled Page” 
%><asp:Content ID=”Content1″ ContentPlaceHolderID=”head” Runat=”Server”></asp:Content><asp:Content ID=”Content2″ ContentPlaceHolderID=”ContentPlaceHolder1″ Runat=”Server”><%  Morphfolia.PublishingSystem.WebFormHelper webFormHelper = new Morphfolia.PublishingSystem.WebFormHelper();lblProperties.Text = webFormHelper.Page.Description;%>

<p><asp:Label ID=”lblProperties” runat=”server”></asp:Label>
</
p>

<p style=”border: dashed 2px red”>CustomProperties Count: <%= webFormHelper.CustomProperties.Count.ToString() %></p>

</asp:Content>

(5) Your code behind or WebControls call functionality in the Publishing System

You can also (as you’d expect) use the Morphfolia API’s from the code behind in MasterPages (as shown here), WebForms, UserControls and in WebControls.

public partial class SimpleTemplatingTestMasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgse)
{
Morphfolia.PublishingSystem.WebFormHelper.LogRequest(HttpContext.Current);
Morphfolia.PublishingSystem.WebFormHelper webFormHelper = new Morphfolia.PublishingSystem.WebFormHelper();
litPageHeading.Text = webFormHelper.Page.Title;
}
}

(6) Your code behind calls Morphfolia Business Logic

The Publishing System (including the WebFormHelper) exist to bring consistency to your site or application – by allowing you to skin WebForms and ‘content’ from Morphfolia using the same underlying mechanisms (PageLayouts and so on).

Another option available to you is to go straight to the Business Logic and use the APIs in a more isolated manner (rather than using the ‘normal’ Morphfolia website (with it’s publishing section and so on).  Although it depends what you’re aiming to do you might want to do this to leverage:

  • The CustomPropertyHelper or StaticCustomPropertyHelper
  • The ContentIndexer or SearchEngine
  • Or maybe just the Constants

Using the Business Logic APIs you can create WebForms that go straight to whatever core functionality you want.

(7) Serve up your WebControls via HttpHandlers

The default HttpHandler provide with Morphfolia is responsible for serving the majority of user facing pages, including both administrator defined content and the ‘special’ pages (Search Results, Site Map and Site Index); all of these special pages simply creat an instance of a WebControl and write it to the output stream.

You can do this by modifiying the default HttpHandler or writing your own (use the default one as a starting point).  Here’s how the default HttpHandler does it (in this case to serve out a TagCloud, which the current pageLayout will place where ever it’s been told to); the default Httphandler uses a simple switch statement that checks the PageName and instansiates a particular WebControl as required:

case“tags”:Morphfolia.Business.ContentIndexer contentIndexer = new Morphfolia.Business.ContentIndexer();

Morphfolia.WebControls.TagCloud tagCloud = new Morphfolia.WebControls.TagCloud();

tagCloud.NumberOfTagDivisons = 15;
tagCloud.MinimumOccurranceThreshold = 20;
tagCloud.Words = contentIndexer.GetWordsForTagCloud(tagCloud.MinimumOccurranceThreshold);
tagCloud.NavigateUrl = string.Format(“{0}/SearchResults.aspx”, WebUtilities.VirtualApplicationRoot());

tagCloud.NavigateUrlQueryStringKey = RequestKeys.SearchCriteriaIndentifier;
pageLayout.ChildControls.Add(tagCloud);
break;

And in case you’re wondering, this is (basically) how you get an HttpHandler to serve up a WebControl:

public class DefaultHandler : IHttpHandler
{
StringWriter sw = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(sw);
Morphfolia.WebControls.WordIndexListPresenter wordIndexListPresenter = new Morphfolia.WebControls.WordIndexListPresenter();
wordIndexListPresenter.RenderControl(writer);
httpContext.Response.Write(sw.ToString());
}

(8) Your WebControls can leverage morphfolias Business Logic APIs

This is bascially the same as Option 6, except that by using WebControls your functionality can be easily re-used in multiple systems, and can also be served out through HttpHandlers (option 7).

(9) Your Business Logic calls the Morphfolia Business Logic

You can also work at the Business Logic level; develop a complex application of your own that uses some of the logic in Morphfolia.  You can, of course, also call the logging methods provided in the Buisness Logic – or the under-lying methods in the Common assembly; this will help isolate changes in the logging providers (the MS Enterprise Libraries).

(10) You Business Logic calls the Morphfolia Data Provider via its Interface

If you like the MS SQL DataProvider you can call it directly (preferably via the interfaces located in the IDataProvider assembly)

Notes

  • There are a variety of Helper classes in the Publishing System, Business Logic and Common assembilies; they’ve mostly been written with the intent of being used by external code.
  • The one major integration point missing is a WebService facade.  There currently aren’t any plans to develop a WebService facade in the immediate future – although this would change if enough people contact me asking for it 🙂