StatisticsTotal Posts: 34 This Year: 0 This Month: 0 This Week: 0 Comments: 0
Recent Posts
On this page....
Archives
Full Archives By Category
2007 Calendar View
| April, 2009 (1) |
| March, 2009 (2) |
| February, 2009 (3) |
| January, 2009 (2) |
| November, 2008 (3) |
| October, 2008 (4) |
| February, 2008 (1) |
| December, 2007 (2) |
| November, 2007 (5) |
| October, 2007 (2) |
| November, 2006 (4) |
| June, 2006 (1) |
| May, 2005 (2) |
| April, 2005 (2) |
Categories
Admin
Sign In
Acknowledgments
DasBlog Theme Design by: Tom Watts
E-mail:
Theme Image by: dreamLogic
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.
|
 Sunday, April 05, 2009
This blog post is part of a series of blog posts concerning a Clean Code study circle that we developers at Admeta are persuing during 2009. Here you can find an introduction concerning the question why we are doing this and here you can find an overview of all chapters as well as some study circle recommendations.
Chapter 5 Formatting questions:Coding Convention conventions:- How many characters per line do you think is maximum?
- What resolution do you use on your monitor?
- How do you typically choose to group code in your classes?
- Do you place a caller and callee method close to each other or group them in some other way
- Where do choose to declare your member variables?
Design considerations:
- Do you agree with that "protected variables" should be avoided? Why / Why not?
- How many rows do you think a class can have before your warning bell start to ring that it might be too big and do too much?
- Is there any reason you can think in which instance variables should be placed anywhere but at the top?
Questions to ponder upon:- The chapter emphasizes quite a lot on grouping code together that belong together. (Vertical Density p79, and Conceptual Affinity on p 84)
- What different group categories do you use and why?
- Where do you draw the line between grouping code with regards to functionality in a class and extracting a group to a new class (according to the Single Responsibility Principle)
- Do you agree upon that all developers in the team should agree on single formatting rules.
- Where do draw the line of agreement?
- How do you select which rules to apply? Voting or something else?
- What on earth is a ”Hollerith limit”?

 Sunday, March 15, 2009
This blog post is part of a series of blog posts concerning a Clean Code study circle that we developers at Admeta are persuing during 2009. Here you can find an introduction concerning the question why we are doing this and here you can find an overview of all chapters as well as some study circle recommendations.
Chapter 4 Comments questions:
Reading quiz:
- What does Robert Martin mean when he writes that comments lie?
- This chapter contains 8 different categories of good comments. Which ones do you remember?
- Likewise there are 18 categories of bad comments. Which ones do you remember?
Chapter 17 "smells and Heuristics", lists 5 categories of bad comments (p.286)
Questions to ponder upon:
- One good comment is the "todo comment" which has tooling support in Visual Studio.NET. There is also tool support for using the "Hack" comment (e.g. //Hack: this code should be cleaned up when there is time for it). Do you think this is a good comment to use if you don't have the time to clean the code to a good design?
- Setting a function comment has the positive side effect in Visual Studio that the comment is visible with the so called Intellisense (auto-complete). However, there is a limit to how long a sentence can be in order to be showed in the intellisense. One could argue that a valid comment would need to be long in order to say anything that the function name itself does not convey. Do you agree or disagree?
- What is/has been your reason for commiting commented-out code to the source code repository?
- If you are implementing an algorithm that is more complex than usually, do you prefer to document that algorithm as pseudo-code as a comment close to the implementation of it? Why/why not?
The context of our study sessions is restricted to .NET and C#.
 Monday, March 02, 2009
This blog post is part of a series of blog posts concerning a Clean Code study circle that we developers at Admeta are persuing during 2009. Here you can find an introduction concerning the question why we are doing this and here you can find an overview of all chapters as well as some study circle recommendations.
Questions: Chapter 3 Functions
Reading quiz:
- Why should functions be small?
- Why do function arguments take a lot of conceptual powers?
- How do you avoid too many parameters in a function?
- What is temporal coupling?
- When would you make a difference between returning a value from a function and setting the value as a class field within the method?
Design considerations:
- Is it ok to have many different levels of abstractions within the same method / class?
- How do you see C# v3 Extension Methods fit into what Robert Martin writes in this chapter?
- If you don't use flag arguments, and instead use several unique methods, how do you avoid duplication in the code?
- Do you see any design choice in which error codes code be used and still avoid creating a dependency magnet, as well as avoiding OCP violation?
Questions to ponder upon:
- Functions are also sometimes referred to as methods (no return value). Why does not Robert Martin mention methods in the chapter?
- If functions should only contain 6-8 lines, would you prefer not to waste space using {} when you have an if statement followed by a one line block statement?
- Say that a function is doing several things, but these things can be considered as one thing on a higher abstraction level. How do you label that function if you can't find a good name to describe that higher abstraction layer?
The context of our study sessions is restricted to .NET and C#, thus the nature of the questions above.
 Monday, February 16, 2009
This blog post is part of a series of blog posts concerning a Clean Code study circle that we developers at Admeta are persuing during 2009. Here you can find an introduction concerning the question why we are doing this and here you can find an overview of all chapters as well as some study circle recommendations.
Questions: Chapter 2 Meaningful Names
- What do you think is the characteristics of a good name?
- Do you take IDE Code Completion into consideration when labeling namespaces, class names and its members?
- Have you reflected upon "noise words" in names before?
- If you have a class property of type int named Age, but you discover that you would actually want an Age property of type string as well. How would you handle this?
- Are you or have you been using Hungarian Casing? Why? Do you agree with the books statement that it should not be used in modern languages?
- Having a prefixed I for interface is an established Microsoft convention. Do you agree with this? Why?
- Extra (Design considerations): Interface vs Base classes [1], [2], [3], and [4].
- Do you think "Duck Typing" is something good and do you see Duck Typing as possible in a typed language as C# v3?
- How far should we utilise the support for Duck Typing in CS 3?
- Would you consider complexity of code as a beautiful thing or do you agree with the books ways of seeing such practices to write complex code deliberately as a personal quest to show off mental capabilities?
- Is there any benefit of using constructor (or a static factory method that produces the object) as a way to inject dependencies compared to properties/mehtods?
- Design: So you find the concept of Value Object as a useful pattern?
- What is your opinion on PascalCasing and camelCasing?
- Are there any rules in Chapter 17 that you think originates from this chapter?
- Is there any rule that you are missing from what you have read in this chapter?
The context of our study sessions is restricted to .NET and C#, thus the nature of the questions above.
 Monday, February 02, 2009
This blog post is part of a series of blog posts concerning a Clean Code study circle that we developers at Admeta are persuing during 2009. Here you can find an introduction concerning the question why we are doing this and here you can find an overview of all chapters as well as some study circle recommendations.
Chapter 1 Clean Code questions:
- Before reading, take a moment to reflect what the concept of Clean Code means to you.
- Is there anyone of the different "guru's" description of Clean Code (p7-12 + forword) that do you think lies closest to your own definition of Clean Code?
- After having read the chapter, has the reading changed your conception?
- What is your experience / opinion of code generation tools or any other higher abstraction level of programming (4GL)?
- Do you have any good or bad experience of building your own code generator (in some way)?
- Where do you think we are heading when it comes to abstraction levels in languages and tools?
- Do you consider this to be a bright future for us developers?
- extra: What do you think of Joel Spolskys described "The Law of Leaky Abstractions"?
- Have you experienced something like "the Grand Redesign in the Sky" and how did that end?
- What is / has been your explanation to having written bad code (as we all have done!) in the past?
- Do you think it is suitable for us as a team to align to a "School Of Thoughts" (p12) or do you see any better path to having a more uniform clean code conception?
- What do you think of "the Boy Scout Rule" (p.14) applied to code?
- Are you familiar with any or all following Principles of Design (S.O.L.I.D.) (p15):
- SRP - The Single Responsibility Principle
- OCP - The Open / Closed Principle
- LSP - The Liskov Substitution Principle
- ISP - The Interface Segration Principle
- DIP - The Dependency-Inversion Principle
- What do you think is the status of Clean Code at our company?
As a side-note, Robert C. Martin and Joel Spolsky, the two people basically mentioned above, seem to be disagreeing a lot these days (excellent summary here by Niclas Nilsson). I guess they have not read my writing upon the Truth vs the Truth... They seem to have made up somewhat in the end though.
 Sunday, February 01, 2009
Reading the Clean Code book, as for reading any book really, is not just about reading and understanding. It is also about reflecting on what is stated and translate it into your own context and experience. I hope that these questions will help you do this.
In a previous post entry I wrote about my idea of starting a Clean Code study circle at work. In this blog post I will collect an overview of the book as we continue our study circle providing links to blog post containing questions for each chapter. I've also posted some guidelines and recommendations for others who are thinking of starting a study circle. I will be updating the list below with links as we go along with our study circle at Admeta during 2009.
Study Questions chapter overview
- Clean Code: questions
- Meaningful names: questions
- Functions: questions
- Comments: questions
- Formatting: questions
- Objects and Data Structures
- Error Handling
- Boundaries
- Unit Tests
- Classes
- Systems
- Emergence
- Concurrency
- Successive Refinement
- JUnit Internals
- Refactoring Serial Date
Some Guidelines for Starting a Study Circle
If you are thinking of starting a study circle at work, here’s a couple of practical advises based upon our experience:
- The topics in each chapter can potentially lead to discussion that lasts for days... But try to limit yourself to the time set out for it. The meetings is not necessarily about reaching a final agreement of every discussion. Instead, look at is as the beginning of a journey to some kind of agreement of a mutual understanding of what clean code is.
- During the hour, we summarize each sub chapter. I.e. some volunteer person for each subchapter summarizes in his own word briefly and objectively what was written. Once done with this, the same person gets to be the first to reflect upon the content. A discussion can follow afterwards.
For us, such a summary/discussion of the chapter would take more than an hour (in both groups). So it is a good idea to tell people in advance what subchapters they think should be focused on in each chapter. Start with these subchapters when you meet!
Most likely, you will not have time to discuss the questions. But you may sneak a question in at a sub chapter discussion.
- As a follow up to the meeting, use some kind of survey tool to poll questions discussed in the meetings. This way you will actually get a statistical backing up of what people think based not only by those who are the most eloquent with words.
I tried out using SharePoint surveys but I don’t like the tool. (I might come back with a little blog post rant on this…)
- If there are many developers, split the group into smaller groups. It is easier for all people to get a chance to say something if the groups are smaller. The person who set up the group will participate in both groups and act as the meeting coordinator and bridge between the two groups.
If several groups are used, I think it is a good idea to rotate the people in it every other or third meeting. Everyone should really know everyone in good working teams.
 Saturday, January 31, 2009
At Øredev in November 2008, I got the opportunity to listen to Robert C. Martin, also known as Uncle Bob. I have been a fan of his work for many years ever since I read his book Agile Software Development Principles, Patterns, and Practices. A few years later when the C# version came out I took the opportunity to reread many of the chapters. To me, that book became a eye opener to a new way of working with code. And I think I am not alone. For instance, it seems to me like much of the ALT.NET movement gets a lot of inspiration from topics found in this book. Like for instance the excellent description of the 6 design principles, now commonly referred to as S.O.L.I.D.
Anyways, in 2008, Robert Martin came out with a completly new book called Clean Code: A Handbook of Agile Software Craftsmanship. Naturally, Clean code was his chosen topic at Øredev for both his keynote and the session on Functions (chapter 3). Robert Martin proved to be a passionate speaker so I was not disappointed. Neither have I been disappointed in this new book so far. Since Øredev I have read about half the book and I truly feel that it is a gold mine to read for any professional developer.
But I kind of stopped reading a couple of weeks ago since I had this great idea. But before I tell you what, I’ll tell you why. That’s usually a good start.
The big WHY
The concept of “Clean” is often defined per developer
This is a bit unfortunate but my experience is that we developers all have different opinion as to what clean code really is. We all get our little habits and our own way to keep our code clean and readable to ourselves. It happens that we shun the sight of other people’s code since it simply is not clean. As in our definition of clean that is.
If only, we could keep our noses glued solemnly into our own written code. Unfortunatly, this is not so.
The common code base
Professional programmers usually don’t work isolated from other professional programmers (although it happens). Most often you share a code base with others and you will have to dig into and work with other peoples code. This is usually where a developers' nose start sneering since, "no way, that code is clean!"
Imagine this sneering nose developers name being Robert. So what does Robert do when confronted with such ugly code? Well, he would probably sneak in a bit of refactoring of the code with the sole purpose of making it clean. That’s ok and quite normal for any programmer to do. So it should be ok.
The only problem is that when Joe, who originally wrote the code, wants to work again with the submitted, now clean, code, he finds the code to be … unclean.
What does Joe do? Well, you guessed right: refactor a bit back to “clean” state. With a big grin of proudness, Joe will resubmit the now clean code into the code repository.
Later when Robert comes back to this code, what does she do? Well perhaps refact............
Verbal Communication
Naturally, we developers aren’t idiots (although it may perhaps seem so occasionally to non-devs.) and we do have a mouth for other purposes than to shovel food and drinks into it. So in the end, Robert, or Joe, will walk over and talk to eachother. This is where the "big discussion" may start. What is clean and what is not clean code.
It may sound like it would be a heated and most dreadful debate. But I think most developers actually like discussing these things. As long as you are able to convince the other guy of how beautiful and logical your clean code is. However, most of the time, this agreement does not occur and the constant battle of Clean Code carries on.
In the end, developers may stay away from other peoples code since it is tainted by uncleanness.
The Contract
Naturally, the previous description is not a successful situation to have at a company. The code base must be shared for lots of reasons; work scalability and fresh influences to name a few. So many companies bring out code policies, written in a document for all developers to see and sign on. In blood. Code inspection tools, like FxCop, will run at night and report to everyone in the morning if someone has violated the signed contract of Clean Code.
Naturally, the contract has got to come from somewhere. There are a couple of different ways
A) The company chief architect(s) brings forth the document for all developers to follow.
B) All developers join in big battle lasting for days and come up with a final agreement.
C) The company borrows someone else’s contract.
Naturally, C) is the most common option. But there will always be room for B) and A) since there are domain specific stuff that still can be agreed upon.
The idea – the WHAT
At Admeta, where I work, we are using the Scrum project methodology and we are fairly agile in the way we work. We are using model C) as in the Microsoft conventions and guidelines and we also have a wiki page with further conventions agreed upon, i.e. B). We do not believe in the A) alternative.
So naturally when I began reading the book, it became clear to me that I would be doing an awful lot of referencing to the book when discussing clean code with my collegues. Very soon I thought, my colleagues would get very tired of both me and Uncle Bobs opinions (although they all heard him speak at Öredev) and tell me to put a sock into my mouth... What a dreadful scenario!!! So naturally, I was forced to get an idea. And thus it came to me one beautiful day:
The idea: So why not try to make everyone read the book and we will have a discussion for each chapter? I have previously been participating in a group doing exactly this at Dotway with the GOF Design Pattern book. To me Clean Code seems like a perfect topic and we could probably gain a lot as a company and individuals if we spend some time doing this together.
The idea – the HOW
Said and done. I talked to my colleagues and every developer on the company has now joined. Everyone has got an own copy of the book (it’s actually very inexpensive) and we get an hour once a week on company time to do discussions. Reading is done on spare time, but hey: it is fun reading! Besides, each chapter is quite small and would take little time to read.
So this Thursday, we’ll have our first Clean Code discussion meeting. As a preparation, the meeting attendees will have to read Chapter 1 of the Clean Code book. I have also given them the following questions to reflect upon:
- Before reading, take a moment to reflect what the concept of Clean Code means to you.
- Is there anyone of the different "guru's" description of Clean Code (p7-12 + forword) that do you think lies closest to your own definition of Clean Code?
- After having read the chapter, has the reading changed your conception?
- What is your experience / opinion of code generation tools or any other higher abstraction level of programming (4GL)?
- Do you have any good or bad experience of building your own code generator (in some way)?
- Where do you think we are heading when it comes to abstraction levels in languages and tools?
- Do you consider this to be a bright future for us developers?
- extra: What do you think of Joel Spolskys described "Law of Leaky Abstractions"?
- Have you experienced something like "the Grand Redesign in the Sky" and how did that end?
- What is / has been your explanation to having written bad code (as we all have done!) in the past?
- Do you think it is suitable for us as a team to align to a "School Of Thoughts" (p12) or do you see any better path to having a more uniform clean code conception?
- What do you think of "the Boy Scout Rule" (p.14) applied to code?
- Are you familiar with any or all following Principles of Design (S.O.L.I.D.) (p15):
- SRP - The Single Responsibility Principle
- OCP - The Open / Closed Principle
- LSP - The Liskov Substitution Principle
- ISP - The Interface Segration Principle
- DIP - The Dependency-Inversion Principle
- What do you think is the status of Clean Code at our company?
I think these questions will be more than enough to discuss for our meeting so we will probably end up choosing the most interesting ones to discuss. I am truly looking forward to it.
Btw, I'll be continuously posting my questions for each chapter on this blog. So stay tuned if you are interested.
 Saturday, January 17, 2009
Some 20-25 years ago as a teenager in School, a teacher once told me and the rest of the class the following metaphor.
Two persons look at a roof top and distinguish a bird sitting at top of the roof. The distance is far so it is difficult to see the details, but one of the persons suddenly says: "what a beautiful peacock!" The other one looks at him bemused and says "that's not a peacock. It's a rooster!" Then the two persons burst into an argument on this matter which lasts for quite some time.
What my teacher then told us is something important I think: Sometimes the truth is different for different people, but each version is still a truth. It is important to remember, and respect, that there may be different versions of the truth which are correct in their own way.
I have come to reflect upon the essence of this very often over the years and I feel I would like to write some fine grained aspects of it:
The truth is context dependent and it is not always absolute.
Both persons actually believe themself to be right, and in a fundamental way, they are therefore both correct. In order to understand this perspective it is vital to consider the context. The context in this example is quite complex since you must take into account things like eye sight capability and what the actual conception of what a rooster and a peacock are. Nevertheless, the person with poorer eye sight or perhaps lesser bird knowledge, still perceive his belief according to his own context. That makes it a truth. Valid in a specific context.
Most likely, you are thinking the same thing as I have been thinking for so many years: There is always an actual correct truth to be found. Take mathematics which should be as a good example. There is always a correct answer to a calculation, right? I mean, 1+1 will always be equal 2, don't you think? However: If the context is Boolean logical mathematics, 1+1 is actually equal to … 1. So whatever truth you think you have, someone may pull a rabbit from a habit bringing a completely different context into the picture which will make your established truth completely wrong.
If the two persons go closer to the building they probably will discover that another truth exists. This is actually where the story continues:
The two men found they could not reach an agreement so they decided to walk closer to get a better look. Soon they realized that it was not actually a real bird, but a statue of a bird. More than that, once they got to see the details neither of them could really tell what kind of bird it was the artist had meant to depict.
Ah! Now we are getting closer to reality I think. Certainly there are better truths that can be found when digging deeper. But very often we find ourselves in a situation where we have to accept a good enough truth. A truth that works for the applicable context. This is a practical truth.
Let us turn our attention in another direction for a while.
Always choose the most important topic in a discussion.
Have you ever found yourself having several discussions going at the same time with someone? Well, unfortunately it occasionally happens to me. Before having reached a consensus from an initial disagreement of opinions, the next disagreement comes up. To make things even worse, the knot to untie the first disagreement depends upon the second disagreement to be settled first. This can continue in an evil spiral of disagreements until you find yourself arguing over 5-6 very different things at the same time. I always hate when I find myself in these discussions since there are too many variables to categorise and sort out. I beilieve that this is one of the obstacles that make discussions such a difficult art. When this happens, there is ususally a call for a time-out in the discussion I think.
But let us turn our focus back to the two persons again. The first person said that it was a beautiful peacock. A bit speculative perhaps, but his main point was probably that it was beautiful, not necessarily that it was a peacock. This would be the main sensation he had and most likely the feeling he wanted to communicate. But by doing so he found himself ending up in a discussion that probably had nothing to do with his original sensation. If the two persons enjoyed the bird discussion and considered it as meaningful, perhaps it was a fruiteful one. However, I think they hit a a side-track and discussed a less prioritised issue. If this is so I think both persons could have given in earlier by saying something like “oh, perhaps you are right”. Then they could have focused on the original and probably more important message: beautiful or not…
Although the story is a vague example on this, I think we often do tend to discuss less meaningful things just because of curiousity or a sheer willingness to be right. Instead, we should focus on the stuff that matters within the important context!
I’ve met some people who loves throwing arguments in a heated discussion and who might even provoke a person in order to get it. I’ve also come across some people who have even lied about their true opinions in a discussion since they wanted to test the opponents’ arguments. This discussion tactic may be a dangerous road to walk. In the end the person often end up confessing that he had not really been arguing with his true mind. If these types of discussions keep reoccuring with the same person, unfortunately my trust fades away. Do you want to spend your time discussing something with someone in whom you have no trust?
So let us get back to a final aspect of truths in a discussion.
Considering someone elses truth is about showing respect and having patience.
With this aspect in mind it becomes a whole lot easier to actually listen to people in a discussion/argument. Quite clearly, the more confident of an opinion we become, the more difficult it is to be open and appreciate different ways or slightly different truths.
I think that listening and appreciating other peoples truths is the most important ingredient in a discussion. You will never truly "win" a discussion if you don't pay the other person respect by giving him proper feedback showing him that you are actually listening and understanding his truth. And by saying paying respect, I dont mean shoveling a line like "yes, perhaps you are right, but..." and then quickly head on to your main point. That's nothing!
I would dare to say that showing that you listen to someone is a very physical thing. People who are good at this highlight this attention using their whole body. We normal mortals mostly have to stick to the use of our eyes. Your interest and intention should very clearly be shown when you meet the other persons eyes. A bit of a magic trick to that wordless communication phenomena, but eye contact communication does actually work in this sense. That is how you are showing your interest in his version of his truth. Not by opening your mouth quickly and say something stupid like "yes, but"...
I also think it is best if this effort is sincere and not just a plan to get your own point across. Be open to that you both have a version of the truth (or even that you can be wrong) and you will both probably gain a better understanding of a deeper truth in the end.
I firmly believe this is the key to successful communication and I am constantly trying to become better at it myself. It is not easy in the heat of the moment in a discussion. And I must admit I sometimes fail due to lack of patience... But, hey, the road to perfection is a long and fun one to walk!
 Sunday, February 03, 2008
In a previous blog post, I covered the following topics:
· Published, not stored which basically allows for more people to read the document.
· Refactoring structure allowing for documentation to stay agile and up to date with a current content and structure.
· No special roles, instead accountability for taken actions!
· WYSIWYG vs. wiki syntax basically stressing that simple editing markup is good enough for most types of documentation.
In this post I will instead dig into the following two topics:
· Local feedback which allows for history of decisions to be associated to the source of the information.
· High cohesion and low coupling is a well known programming principle. I think this principle can be applied to documentation as well which is better supported with wikis than in file based documents.
We sure do communicate with each other a lot at our job. This is mostly done in a synchronous way with verbal communication. Most often agile methodologies favor verbal communication over written communication since it is considered as the most effective way.
However, there are other ways of communication which are of an asynchronous nature. Such communication allows us to write information or questions to other people and do other things while waiting for the response to come back.
Asynchronous communication also allows for us to take the time to formulate a good text that correctly describes the important part of the message. Sometimes this is a great strength over verbal communication since in an intense moment we do tend to talk past each other, not understanding what the other person is trying to say. Of course it can also be a weakness since we don't get an immediate feedback of what we are stating. But this is a completely different blog topic which I probably will write eventually.
However, an example of such asynchronous communication is of course mail, which probably still is our most commonly used communication tool at companies. Yet another example is some kind of chat messenger like MSN Messenger or ICQ which also is of an asynchronous nature. In fact you can find yourself having a multithreaded dialog with someone on a chat application with several topics being discussed at the same time. At least, I know that we programmers often do this. Very effective indeed! 
So what about wikis? Let’s look into this now:
Local Feedback
I would say that we often use mail to communicate with each other at work since the asynchronous nature is convenient. However, one disadvantage is that important information as to why we reached a certain decision is persisted in our mail box only. Unless you are extremely organized with a myriad of mail folders, it will become difficult for you to find this mail conversation later on.
I find that even searching for mails, as gmail states as a big strength of functionality, many times this does not work because I can’t remember the exact words to use in the search... In this case I am left with my structured mail folder hierarchy in order to find the message. After a couple of years there may be thousands of emails in each folder… But then again, perhaps this is only a problem that I have… 
Another issue is that information is not published for others to read apart from those in the recipient list. At least for some topics, the information has to be brought out and written somewhere else where more people can read about it. I think that some ”non-secret” topics instead could be published and discussed directly on a wiki omitting the mail dialog. Many wikis offers comments or some kind of discussion board to be associated with the wiki page that can be used for this.
One wiki that successfully uses this approach is Wikipedia. Since everyone is allowed to enter information in Wikipedia, naturally, conflicts of opinion occur frequently. Take a look at this page for instance and please notice that it is the discussion tab. The page contains the discussion of what Inversion of Control is and how it could be explained etc. Unfortunately the meaning of the term is very different from programmer to programmer as you can see. But with discussion, eventually a mature and natural consensus can be reached as to the meaning of the term (ubiquitous language established, see this blog post). Unfortunately not yet so for IoC.
However, the essence here is that the information as of how the meaning of a term was concluded is stored locally and connected to the information itself. I.e. effective metadata! I think this is a great strength.
Naturally, there is always a decision to be made what discussions are to be held in public on a wiki and what discussions are to be held in mailing lists. I am not arguing for abandoning mail here! 
High Cohesion and Low Coupling
I would dare to say that all programmers have heard this statement (and if they haven’t, it would be time to do a little bit of studying. ) However easily stated it is not as easily achieved. I also dare to say that it takes years of programming before getting skilled enough to realize the importance of the statement as well as knowing how to apply it well.
I have often reflected upon lately that successful communication should apply to the same principle. When explaining something to someone, we have to stay focus on the topic. Otherwise, we confuse the audience with too much information (information overload). Sometimes we need to explain a side track in the discussion before we get to our main point. Recognize this scenario? Well, it certainly is the difficult art of pedagogic and it is the importance of having common reference knowledge.
Perhaps being a little bit daring, I think the interpretation as to the meaning of high cohesion and low coupling is quite similar when it comes to communication. Looking at a story to be communicated to someone else, the main focus lies in the main message you want to get across. This information could be compact, i.e. high cohesiveness, which will make it easier to understand. But it often relies on other information, I.e. it is coupled to the other information. Naturally you would like high cohesion and low coupling to get the main point across quickly. But this coupled information is often what makes the story complete in its context and it gives the story its nuanced and interesting flavors; although making it more difficult to understand.
Having established this interesting parallelism, let us turn an eye in the wiki direction. I have already established in the part 1 wiki blog post that refactoring of the wiki structure is an easy thing to do. This is important since it allows for us to provide pages that have a high cohesion. High cohesion in wikis is pretty straight-forward to achieve since the page refactoring support is there.
However, the thing to look out for is strong coupling. Although a good wiki should be able to update linking between pages when you change them, you may run into many fragmented pages with too many links (high coupling) to other pages. This is where your sense of structure and judgment comes into the game. I dare to say that there is no tool that can do this structuring automatically for you since no tool can predict exactly what you will write.
This is nothing new really and I believe that every good communicator has come to realize this and applies to this principle whether it is in writing documentation or merely speaking to people.
In my next, and perhaps final blog post about wikis, I will have a more practical approach as to how to choose which wiki to use (there are lots of them out there). I can’t say I am an expert of all those wikis, but at least I’ve learned some aspects to look for. So until then, stay tuned.
PS. I probably should admit that my interest in blogging on other topics recently has gained which I might prioritize writing (as well as time spent not blogging… :(  . So if you are interested in number 3 in this series, please let me know and I’ll try to speed up the persistence of that story.
 Monday, December 10, 2007
I started out this web 2 series with a rather general introduction here. However I have to admit that I wasn’t very specific, nor pragmatic in this blog. This has got to change right here because for me web 2, and especially wikis, is all about a pragmatic approach:
The ability to document necessary and important information and allowing for as many people as possible to read, edit and give feedback upon this information.
This is collaboration. This is wikis.
Unfortunately, documentation often has a poor sound to it these days with the agile winds blowing in the software industry. Don’t get me wrong, these agile winds are definitely good and I think we are on the correct path here. However, I think there still is a need for some documentation. Only, the documentation has to be as agile as the process of developing the code itself. This is where wikis come into the picture as a better documentation persistence tool.
The traditional documentation approach is by using a file-based storage for content. Usually the tool is some version of Microsoft Word which is probably what 90% of what people are using. The editing functionality in this tool is excellent. However, I do recognize a number of weakness as I will note down as I go along comparing file based storage with wikis.
Published, not stored!
A wiki is always reached via a web browser. Therefore, when writing content on a wiki, it is naturally published on a web server for all authorized users to see. This is a great strength since everyone these days are used to a web browser for localizing information.
File based documentation is however often a pain to even locate on a company. Often, such files are placed on a file server somewhere in some obscure directory. Often I find that there are several of these directories too which makes the wanted document even more difficult to find.
However, an interesting approach is Microsoft Collaboration platform SharePoint. Here SharePoint is responsible alone for knowing the actual physical storage of the file and files are only provided as links to the users for download or viewing. This is a lot better approach. Unfortunately, due to licensing costs, a SharePoint solution is often not doable for smaller companies.
Refactoring structure
As when programming code it is difficult to know the exact structure before work has begun. Requirements (input data) may change or you may get new ideas as you work with the code/document. When creating a file based document, the scope for it has to be carefully considered. The information that is out of scope has to be placed in another document which instead is referred to. I find that file based documentation does not leave you much choice for actually editing the scope of the document once you have started working on it. Wikis on the other hand allow you to quite easily refactor the structure and scope as you go along. This since the actual document you are writing is split into several pages reachable via links. It is quite easy to create a new page in a wiki and link to this page which makes refactoring extremly easy. Referencing other file documents in a file document is a much harder this to do. At best you may link to a referenced file document, but this document still probably is a huge source of information so it will still take you quite some time to locate the desired information within this referrenced document.
This refactoring mechanism is one of the largest benefits with a wiki I think. It allows us to split huge sources of information in one document into several documents that are easily linked to from other pages. There is a striking similarity here to the software design Single Responsibility Principle. A class as well as a document should only have one reason to change…
No special roles, instead accountability!
Usually, a wiki does not divide people into authorized and unauthorized groups of people. Naturally, only the group with interest in the wiki may gain access to it. But aside from this authority level, everyone in the group may write whatever on the wiki pages. Usually, this would go for the whole company as long as there are no specific security reasons to conform to.
However, although anyone can edit any page, a wiki should always provide an easy way to see what was edited and by whom. This means that accountability is there since it is always possible to see and compare the different versions of a wiki page. Also, wikis should provide an easy way to roll back to a previous version of a page.
Having security restrictions often lead to more maintenance and trouble than what it is worth. If there is no top secrets on the page, let people view and edit the information as they want. If a change was bad, well contact the person for a verbal discussion and hopefully roll back the page afterwards after you have agreed upon what should be there.
As far as I know Microsoft Word does not provide any version tracking possibility on file level so this is often added manually in the file instead. However, the SharePoint platform does give you a versioning and roll back possibility for word files. However, I don’t actually know if it is possible to compare different versions of the word file with each other.
WYSIWYG vs. wiki syntax
Microsoft Word offers WYSIWYG editing. I.e. What You See Is What You Get. It means that MS Word hides the small symbols from us that make bold text go bold and underlined etc. I think MS Word does an excellent job at this (although there are still bugs) and the application has definitely reached a mature status.
I would say most wikis are not mature when it comes to WYSIWYG editing. They are far from as feature rich as MS Word WYSIWYG and often you find yourself cussing over a behavior or a bug that you are used to in MS Word. I believe WYSIWYG in wikis will probably mature during the next couple of years and that the difference will disappear.
However, the WYSIWYG editor, if even provided, is often not what the wiki user utilizes (at least not if he is a programmer searching for control of the tool…). Instead he goes directly for the wiki syntax which is simple to use. Unfortunately, there is no standard here and the syntax varies between different wikis. Bold letter in some wikis would for instance be rendered by adding a star between the word: eg. *This text would become bold when the page is saved and published.*
And a small summary
Well, I have lots more to write about wikis but this will have to wait for a future blog post. Probably, this is even now to long for a blog post. Hopefully someone is reading this eventually. And if you do: stay tuned for more…
 Sunday, December 02, 2007
Andrew Hunt and David Thomas have a written a great book called The Pragmatic Programmer. This book covers so much great stuff! Most of the time, while was reading it, I found myself sitting with the jaw against my chest in astonishment of how clearly Andrew and David pinpoints problems and recommendations in software development. I think all seasoned developers would have the same feeling since the problems Andrew and David writes about are well-known, but not very easy ones to actually pinpoint and describe.
As a side note, at the Øredev conference recently, I saw Andy Hunt giving an excellent key note speech opening up the conference. There was quite a number of fascinating subjects he talked about and I hope to be blogging on some thoughts on these subjects in the near future.
Anyway, in the book, the writers bring up a term called software entropy as a force very difficult to avoid for developers. When I first heard of entropy it was actually in chemistry class many years ago. An explosion is an excellent example of a chemical reaction that renders a very high order of entropy. I.e. the amount of disorder of atoms in the explosion is very high in the beginning but rapidly goes back to a low level of entropy. Naturally, this is due to the high amount of energy that sets the atoms in motion.
There is a striking similarity with software entropy I think. When things are heating up in a development team and we are as busy little bees to meet a deadline, entropy is bound to be high. Or at least the risk is very high that the entropy gets high. As a cause of this, Murphy’s Law might appear out of nowhere which seems to be a result of just pure bad luck. But often it is the just the result of high entropy, i.e. the disorder tends to get high as we get stressed out and several accidents happens in a short amount of time.
The writers go on with an analogy to city buildings that are of very different quality in different neighborhoods; some buildings being very clean and neat while others in another area are in a very poor state. This is the effect of “a broken window”. If one window gets broken and it does not get fixed immediately, then soon another broken window will appear; and yet another and so on. Soon the neighborhood will look like skid row and criminality increases drastically.
That this is so, even Swedish governments have concluded. I recently saw a news program stating this very fact. And in the local news paper the same very fact got stated about a neighborhood not too far from where I lived. A whole city block is going to be torn down and rebuild and as a result, criminality is sure to drop it was stated. Well, good!
I think there is an absolute truth in this and that it can be explained with our pride. If you are not proud over the neighborhood you live in, you are not going to respect either the buildings or the people that live in them. But if you feel pride over a good, esthetic environment that surrounds you, you take more care of it.
As for software development, we have the same situation Andrew and Thomas states. If you don’t feel proud over the code that is produced in the project and honor its design, the software will begin to rot. If this happens, sooner or later you probably are going to have to throw it all away and redo the whole thing from scratch.
So, as the authors of The Pragmatic Programmer so wise fully states: don’t live with broken windows. Anticipating that the design of the software is a good one, follow it instead of doing small hacks in order to save time. That time you save may very well be 10 times the time lost further down the road when someone is trying to get the once upon a time nice design to work again as it should be.
I know: Software is never perfect and this is not what the authors, neither I, are saying. However there is a great difference between delivering good enough software and doing “hacks” to the system all the time.
Unfortunately there is a driving force that often makes these hacks necessary: the critical deadline of a promise made to somewhere by somebody by someone... But the underlying reason for this is often due to a crappy or not existing project methodology which is a subject that I won’t dig into in this blog post. However, this spring I probably will write a lot more about this.
 Thursday, November 29, 2007
The first time I heard the word ubiquitous, a sigh of utter and ignorant reluctance went through my mind. I figured that such a beautiful but complex word is absolutely bound to bear an over-complicated meaning to something that perhaps might be very easy. And unfortunately, that killed my interest at the time. Well, having understood the importance of ubiquitous language my interest is gained.
So what does it actually mean? Well, a quick search at my favorite place to look for strange words gives me a hint. When adding the word define: before a word, acronym, abbreviation whatever in google, a search will be done at a number of open dictionaries on the Internet. This is nice since the explanation of the word is given in a number of different contexts which gives me a broader meaning of the word. With this search, define: ubiquitous, 5 different explanations are rendered. The one I choose to show to you is this one:
omnipresent: being present everywhere at once from wordnet.princeton.edu/perl/webwn
In Swedish I would translate this to “allomstädes närvarande” which is even more poetic I think. However, the English translation put us a bit closer on the map as to an understanding of the word, but we’re not there yet. What is omnipresent anyway? Is there really something that can be everywhere at once? Sounds like something I want to be…
Well, speaking about ubiquitous language, naturally we are talking about a metaphor. And after reading about ubiquitous languages in Eric Evans book Domain Driven Design and having combined this knowledge with my own experiences in software development, the pieces actually fall together.
Ubiquitous language is all about sharing a common terminology between people. This is an extremely important ingredient in how we communicate with each other. Without a common terminology there is no way that anyone can explain anything to anyone else. Or at least it will become a very, very difficult thing to do.
Let me take an example of this. Imagine that you are about to explain to you six year old son how he is to ride his new bicycle. Only that you are not allowed to use any words that actually describe such things as pedals, wheels, and stepping on the pedals. Of course you can always point at the things and call them “thingie” but try doing that as you let go of the bike and let him take off on his own. Well, he is bound to crash the first couple of times anyway so I guess this doesn’t matter that much…
It is hard to find good illustrative examples, isn’t it? Well, I am working on my imagination in this area.
Anyway, in software development we have something that is called the domain knowledge. This is the core business knowledge that is associated with the application(s) to be built. Each company have their own business knowledge and thus also their own specific terminology for it.
However, unfortunately the same terminology is not always used across the company and towards customers. Marketing people will use some terminology when they speak to customers when they originally sell the terrific idea. Then developers probably name those very same things to something similar in the domain architectural design. Then suddenly, further down the road, marketing renames a domain term to something else much cooler and, u-hu, the developers are doomed… They feel that this name change is just not worth the pain of changing it in the software design also. Especially this is common when we are talking the database with live production data. Ouch, do not touch it, it may fall apart and it is deadly vulnerable, the heart and soul of it all etc… Once this name conflict has occurred, the terminology is not shared any longer. Instead all developers have to map their domain names to what marking people means with the provided functionality. This is an utter source of confusion.
Of course, a name change is not the only reason for a mixed terminology at a company and there are certainly most often more players involved than merely developers and marketing people. Lacking communication within a company or misunderstanding of the domain model is just as common source of a fractioned terminology.
So where does ubiquitous “thingie” come in? Well, the terminology that we use to communicate with each other should be as understandable and sharable as possible to everyone so that the same words for describing domain knowledge are used. Then we have a much better chance of actually understanding each other. Trying an illustrative metaphor again; it means that we could concentrate on fitting the puzzle together with the help of the puzzle images instead of trying to do the same thing merely using their geometrical size. At least this is the sensation I get when working in such a domain at a company.
If you know of and understand the domain model and you are about to explain it to new-comers in the project, then my advice is that you start with explaining the terminology being used in a document. This will make it easier for other to understand the domain since they can start by reading this before they get an explanation of what the applications actually does. Otherwise, you will most likely use specific domain language words in your verbal explanations that they have not have heard of before. This will probably make your audience miss the main points you are trying to get across.
Also, by extracting and writing the terminology you will get a better perspective of the domain that you consider as natural and simple but perhaps is not. Most likely, you will find names that are confusing and duplicate names meaning the same thing. If so, revise the terminology so that it is correct and up to date. Make sure that this is the terminology that is used throughout the company by discussing with people. Then you achieve a ubiquitous language which will let you stay focused on the real problems and how to solve these.
 Thursday, November 15, 2007
I started out the chronicle that I recently wrote giving an angle at the information society we live in today. This is also what I will cover as a starter in this first web 2.0 blog post.
For developers, the information society is very real indeed since the knowledge base required for programming is huge these days. I have only been in the industry for about 10 years, but even in this time I can surely notice the change from when I began. In the .NET field alone, which is my field of specialty, there are thousands of classes that are good to know of. It is not always that documentation provided from Microsoft covers the need that exists. Also, the number of frameworks, libraries, components, third party open source products, tools etc seem to have exploded the last couple of years. It is not easy these days to call yourself an expert developer of .NET; Nor in any other programming domain for that matter. Most, if not all, people don’t call like to be called experts in such a broad field because of the expectations it may raise. My experience is that an overall humble attitude resides when it comes to programming knowledge nowadays. Something that is quite alright I think. We should be humble for the unknown I think.
Anyway, for developers, the provided information on the Internet has become a reliable source of information. This includes blogs, communities, articles, wikis etc. There is less of a need for developers today to keep track of all intricate details of language and frameworks since there are so many resources available out there. So many people share their experience in blogs and communities which many times makes is quite easy to find a solution to a specific problem.
However, we do have to distinguish between semantics and syntax. Syntax being the language we program in and I dare to say knowledge of the Frameworks provided to us; Semantics being how we program in the language and Frameworks. Both types of knowledge are to be found on the Internet. Semantics, however, is so much harder to learn than syntax knowledge. Semantics deal with the architecture and the design of software and this takes knowledge (lots of reading) and experienced practice (lots of programming). We are talking years of studying and programming in a professional domain specific environment. The funny thing is that even though I think I’ve reached perhaps the middle of the tunnel, occasionally it seems like I am thrown back to the start of it due to some new experience or gained knowledge. What other profession allows you from time to time to have the sensation of being a rookie again? To me, this is fun. And frustrating.
Well, this blog post kind of made the introduction of what I am hoping to become a series of blog post in the web 2.0 field. I have many thoughts to share, especially when it comes to wikis as software development tool in software projects. So stay tuned for upcoming post if you’re interested of my thoughts.
 Tuesday, May 03, 2005
Today, I ran across several disturbing usability issues using the version handling tool ClearCase. I was to deliver some bug fixes I've made in an older version of an application in a developer stream to a newer version of the application in another stream using the deliver to alternate stream operation in QlearCase. This is certainly a very valuable operation and since this was the first time for me doing so, I was full of steaming anticipation. I thought, "...just a few clicks and I am home free. No cut 'n paste the ol' fashion way. Hell No!"
I had three bugg fixes in the old version. I figured that I could select these three specific work orders, click on deliver to alternate stream and voilá: I'd get some nice merge code screen shoots in which I could select the code to deliver to the main integration stream in a simple way. I've seen and used the merge view in ClearCase before so I knew this would be a breeze.
First issue: ClearCase would not let me choose only the three work orders that contained my bug fixes. I had to pick all work orders, including some other irrelevant stuff that I didn't want to integrate to my main integration stream. Ok. Fine! I'll do so imagining some extra clicks here and there in the merge view.
Some ~250 click procedures later in the merge view, an increasing awareness arose that something was probably deadly wrong. I had been changing some Controls properties in my user interface which meant that many .resx files had been changed. Further more, I seem to have had my Visual Studio.NET project files checked out for either adding or deleting files. Ok, I'll take the pain I figured and continued to click away... All of such changes would be button number 3 anyway (see algorithm below).
Some ~350 click procedures later my brain, set to 'algorithm mode', started looking for a way of improving efficiency. I define the clicking procedure algorithm accordingly:
Step 1: Move the mouse to the "arrow" button. Step 2: Click! Step 3: Move you mouse to either button labeled "2" or button labeled "3". Decide this based upon the merge view. Mostly 3. Step 4: Click! Step 5: Goto step 1. 
Anyone who has performed this algorithm a couple of hundred times knows that your arm gets tired from moving the mouse. It would be much nicer finding a keyboard shortcut for at least one of the clicks. And, voila! There it was: Alt + "Arrow right" for clicking the "arrow button". Now, most keyboard I know of, there is a certain distance between the 'Alt' key and the right arrow key approximately consisting of some 20 cm. If you don't play the piano or otherwise is skillful at playing the classical guitar, you will have to use two hands. It doesn't take an Einstein to figure out that my algorithm is worth crap with this approach. I still would have to move at least one hand back and forth. Issue #2 as you might guess.
Light bulb!!! Unfortunately it didn't come from me :o) but from a colleague of mine, Mattias Ask: "Put a heavy something on the Alt key." Tada! My heavy wallet finally found a superior purpose other than containing receipts and, thank good, heavy coins.
Damn! The speed is up! 400! 500! 600! 700! Heavens! Does it ever end? A growing suspicion in my mind tels me that it isn't and that I should chicken out and abort. Yes I'll do so! I dare no longer. Just think if something go wrong and I have to undo some 1000 click procedures manually in the code.... Oh, Abort, abort! --- Hey! Wait a second... There is no clear way of aborting this thing and perform a rollback operation. Guess what the third (!) issue is? :( Coming to some Rational sense, I realised there was never any risk of having to undo a thousand clicks manually. And I started to click away again.
Well, I did give up anyway. :o( Even though not so time consuming I never was much for repeating dull tasks. In the end I did find a way of aborting: just closing the merge views as they appeared finally led you to a button with some kind of abort labeling (forgot the exact name). Doing so makes it possible to continue at a later phase. Ok, so I tried that just to see if it was working. Sure enough it did. But ClearCase got confused with three of my remaining files and refused to accept my choices (button "3" off coarse). I guess that makes my fourth devastating issue. So in the end, after some perhaps 1000 click procedures, I ended up with a complete failure. Here we go: back to the good ol' cut 'n paste. Someone recalls my previous blog about technicians sometimes preferring to do things as done before?
I don't like this at all. It seems to me that this should be working, if doing it right. And the fact that it didn't bothers the hell out of me. The most important lesson would off course be to have only one bug fix as one work orders to deliver to an alternate stream. But since I always would have to do this merging graphically there is still one problem as I see it. The main stream containing the later version of the code has normally some continued developed code (that’s why it is the next version, ehh!). And if a delivery from the developer stream to the integration stream has to take place, there normally should be lots of differences between the two versions. In essence meaning many click procedures. I would very much like some ClearCase expert to give me some answer to this question and some advice of 'best practices'. Hello world! Is anyone reading?
 Saturday, April 30, 2005
When I came up with the blog title I figured that I would explain in some more detail what I meant in one of my future blogs. And when I experienced one aspect of what I mean so clearly on a workshop this week, I thought I'd take the opportunity to write about it. I better warn you that this blog is of a more philosophical nature. If you are not in the mood for this you better stop reading right now… 
But before this, as a small taster I would like to add a personal background which might illuminate my standpoint further. Some 6 years ago I acquired a Master of Science degree in Electrical Engineering. Such an educational program includes many different technology areas; A big package of mathematics, physics, electronics, computer programming, etc. All of these technology areas share one common approach of how to pass a course examination. Some problems are to be solved in a preferable way. Looking back, I remember facing the following questions for each new course: What is the problem, where is the knowledge that helps me solving the problem, and finally how do I solve the problem. It is obvious that by repeatedly dealing with these questions in various technology areas you train the ability to extract important information, analyse it in a correct way, and then finally act upon it. The essence of this is that the approach is general no matter what underlying technology is being used.
Looking back now I am happy that I have learnt a technique of how to approach these questions. But I feel that often there was one question missing: why are we solving this problem in the first place? During those years of studies, the answer was intuitively there most of the time and I didn't even have to address the question. But in real life, and perhaps especially in the software development community, I feel that the question why is so much more important, and unfortunately also sometimes difficult to answer. Because when we building a “machine” that in some way or another is to help people, the ground base for its success is all about the interface between the man and the machine: MMI.
Now, I am not saying that programmers tend to forget the important question of why the software is being developed. On the contrary, I think most programmers are very interested of what the purpose is for their developed code. But I do think that we tend to narrow the field of possibilities by immediately thinking in terms of how we should solve the problem. In turn I believe this limits our creativity in terms of HCI aspects. I further believe we tend to stick to solutions that we have implemented before, that we know of and thus also are in control of. Certainly this is valuable since reusing old ways of thinking is both time saving and less prone for failure. But the question the developer always must ask himself is "Are we really meeting the purpose of the software". In essence: Why do we develop this software?
During the workshop this aspect was so clear to me. I held a presentation and demonstration for a group of people of a software application that I am currently involved in developing. This application is a bit special since it is to be used and integrated in many other applications in an enterprise environment. This is probably the worst case scenario for a program since it most definitely will mean that different and possibly even conflicting requirements are set for the application. Now, at the workshop there was me and some other guys from the IT department present. The rest of the people were all either business managers or business analysts as representatives from different application teams that were to use the demonstrated application. None of them I believe have a technical background, but all of them had a very in-depth knowledge of how their applications are to be used and implicitly and ultimately also why it is to be used. During the day, we were all discussing new future requirements of the application. As each new requirement was discussed, I could not help to think of in terms of how it could be implemented. This in turn might have narrowed my mind in terms of end user possibilities.
Now, I believe I am a true-minded technician. And for me not think in terms of possible solutions when I hear a requirement… Would that not be like waving a banana in front of a monkey and asking him to look the other way… ? ;-)
So. In conclusion: I am not saying that we technicians should not think in terms of “how to solve things” when we hear of new requirements. And perhaps thinking in terms of how to solve things should always be our role in the process of creating the perfect software (Is it doable?). But I believe we should always try to be as open minded in terms of possible solutions as possible and that we should have a huge amount of respect for people with better knowledge, understanding, and experience of dealing with this very question. And we technicians should certainly never believe that we understand the reasons for the existence of the software better than anyone else just because we know the details of its current behavior better than anyone.
Having written all this, I have a feeling that perhaps I have just stated something that is evident for all people, including technicians. But I’ll think I publish this blog anyway. Perhaps I come back rereading it in five years and laugh at my thoughts at the time. Or perhaps not…
|