My attitude towards lines of code as a metric has changed drastically during the last several months.
We all know LOC is a meaningless measure for productivity estimation (and here I regard as LOC any simple counting metric on the codebase: it can be "words", "whitespaces", "keywords" etc.). Well, what this metric can show is that you can e.g. sit down and churn out 5000 LOC per evening. The amount of LOC for a given task can differ across languages, so let's consider that LOC is already "discounted" for a language. Still, use of this metric for estimating productivity or project progress is questionable.
One question is that even "optimal" LOC differ wildly across tasks. Adding a cool new feature can be 1 LOC, and refactoring for the sake of beauty can be 10 kLOC. Tests "write themselves", so tests (if you include them into measurement) can add times more than the functionality they test.
But there's more to it.
Adding a feature by using a third-party tool and several lines of code is faster, more reliable and overall "better" than writing it all yourself (which is more LOC). Basing your product on some technology that allows you to make your LOC 10% compared to what it would be without using it is better in the same sense, too. It gives you competitive advantage. I feel that most startups are about it: having an idea that is useful for people *and* for which a technology stack exists allowing it to be implemented with few LOCs and few configs.
It doesn't only apply to the "start". For a startup (and IMO to any product) it's important to maintain the product focused by only adding the necessary features (to fight feature creep and scope creep) which should be as coherent technologically as possible. Common parts should be reused. Codebase kept small.
I started to understant the "functionality is an asset, code is a liability" mantra (the linked post gives cool examples of what I've been trying to formulate abstractly).
Is {0 LOC, 0 added value} better than {N LOC, much added value}? I claim it is if the added value isn't that aligned with the product and worse otherwise, so "0 LOC" is incomparable to "N LOC" in and of itself.
Then why do some people, me previously (I hope!) included, tend to view the "amount of change" as a metric where more is better? Reflecting over my own beliefs, I think there can be at least two explanations. First, I tend to think that there's some "inherent" to a problem amount of work to be done. Seeing big LOC change gives me an idea that something important was done. It's probably not the case, or even sometimes this "something important" can be an important overall degradation. Second, I simply believe that change is always good, and that no LOC means no change.
These days I think neither of the two is the case.
Apr 20, 2012
Apr 4, 2012
right/effective
As Amy Hoy would put it:
Do you want to be right or do you want to be effective.
History is full of failed projects that where “right”. So it will do you no good to be righteous about testing. It’s 25 anniversary of OS/2 so that comes to mind. Don’t forget other like Multics or micro kernel based kernel GNU Hurd.
I’ll let you in on a secret. They were not really better. They only seemed better on the first glance. Kinda like Titanic seemed unsinkable.from here
Ярлыки:
effectiveness
Sep 7, 2011
software project complexity
You are always wrong about the complexity of the project.
You overestimate it, and have been from the beginning. I'm not speaking of the resources needed for implementation, but rather about complexity for understanding (and almost always more resources as a consequence).
It's only that you don't know or have the right tools and you have much more complex understanding of the project. Your design is overengineered. You build a framework for representing graphs etc when a 20-line algorithm would do. Some of the tasks you are solving are no tasks actually with the right toolbox.
If you knew its actual complexity, you'd laugh at how much time and effort is spent at the project, and also how many people work on it. You think — what? Due to some lack of time the way you do is maybe 20% more complex than it would be if only you had time for analysis? Bullshit. It's 10 or 100 times more complex. The problem is other people have an even worse idea.
Following K.I.S.S might be right: there are less variants among simple implementations, and yours is one of them.
You overestimate it, and have been from the beginning. I'm not speaking of the resources needed for implementation, but rather about complexity for understanding (and almost always more resources as a consequence).
It's only that you don't know or have the right tools and you have much more complex understanding of the project. Your design is overengineered. You build a framework for representing graphs etc when a 20-line algorithm would do. Some of the tasks you are solving are no tasks actually with the right toolbox.
If you knew its actual complexity, you'd laugh at how much time and effort is spent at the project, and also how many people work on it. You think — what? Due to some lack of time the way you do is maybe 20% more complex than it would be if only you had time for analysis? Bullshit. It's 10 or 100 times more complex. The problem is other people have an even worse idea.
Following K.I.S.S might be right: there are less variants among simple implementations, and yours is one of them.
Ярлыки:
project management,
simplicity,
software
Jun 4, 2011
Thoughts
Today I've found a sheet of paper where I've written some of my conlusions several years ago after implementing a relatively large subsystem of the system I was working on in a large company.
- To learn you have to make errors. You have to praise error rather than be afraid of it. "If you speak less and less, you'll have to speak more and more" — Cortasar wrote in his "Exam" meaning that not speaking makes the language and your command of it and expressiveness theirof degrade, and losing its expressiveness it makes you build larger texts. So, the same applies to errors: if you do less of them, you'll have to do more later.
- You shouldn't be too clever in trying to overcome a difficulty: a much more efficient way is trying to avoid it altogether. So, you need to think about the nature, the source of the problem. Perhaps *it* can be removed. Being too clever in overcoming problems, seeing at once a (long) path of fixing a problem can obscure a (short) path that bypasses it altogether.
- Relying on data format (think XML) in many different places weakens ability to change (and to support): changes in the format will lead to changing all places of using.
- Premature optimization is the root of all evil (see (2)).
- Data that differ slightly (say, two similar formats) are dangerous. You have to repeat yourself or at least are very urged to (things differ). Alternatively you can work out rules of conversion, but that conversion will most probably break when some change is introduced. Say, we have one source of data and all just works, we don't even think that there's some part of the code that builds another format upon it. We change the source format substantially and things suddenly break.
May 17, 2011
Corollary
Oh, and one simple thing my ruminations lead to is: the prototype must be written by the same people who will write the actual application, or else there's no point in it: the actual developers won't learn anything from it.
Solution by coincidence
Pragmatics have coined a term "programming by coincidence". Generally it describes a way of coding when a developer tries something without inner understanding of why it works, it works, it's considered to be the final solution, the scheme repeats.
It's interesting to look a bit ahead at the moment when the product has grown substantially and is used by the customer: what does the customer have at this moment? And I'm not only speaking about the situation when coding was precisely "coincidental" — it may have been a series of steps slightly compromising design for features with full awareness. It may have been ignoring 10% of requests that will eventually lead to substantial changes in the product. It may have been failure to refactor and redesign along with new requests. It may have been lack of communication with the customer, or customer's drastically altered plans or improper architecture or platform choice.
So, what is it that the customer has in hands? From the purists standpoint, it's probably but a big ball of mud: hard to understand, hard to change, next to impossible to evolve.
On the other hand, it does the work for the customer. It eases his life (or life of his clients) and automates things. Re-doing it incurs additional costs, and some claim that it should by no means be rewritten from scratch, if that is your first intention:
So it's definitely worth something, but at the same time there's something pathetic about it... I think the situation should be cleanly stated by the development team to the management so that they planned for some "curing" phase. And the management — they should probably have some objective metrics that will show them — unless they can "feel" it — that this kind of situation has arisen.
It's interesting to look a bit ahead at the moment when the product has grown substantially and is used by the customer: what does the customer have at this moment? And I'm not only speaking about the situation when coding was precisely "coincidental" — it may have been a series of steps slightly compromising design for features with full awareness. It may have been ignoring 10% of requests that will eventually lead to substantial changes in the product. It may have been failure to refactor and redesign along with new requests. It may have been lack of communication with the customer, or customer's drastically altered plans or improper architecture or platform choice.
So, what is it that the customer has in hands? From the purists standpoint, it's probably but a big ball of mud: hard to understand, hard to change, next to impossible to evolve.
On the other hand, it does the work for the customer. It eases his life (or life of his clients) and automates things. Re-doing it incurs additional costs, and some claim that it should by no means be rewritten from scratch, if that is your first intention:
"The idea that new code is better than old is patently absurd. Old code has been used. It has been tested. Lots of bugs have been found, and they've been fixed. [...]Then, each of the requests successfully addressed is "documented" in the code, by the code (of course there are no tests in our muddy product!). The product can even show this specification of things to the person operating it.
Each of these bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it's like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.
When you throw away code and start from scratch, you are throwing away all that knowledge. All those collected bug fixes. Years of programming work.
You are throwing away your market leadership. You are giving a gift of two or three years to your competitors, and believe me, that is a long time in software years."
So it's definitely worth something, but at the same time there's something pathetic about it... I think the situation should be cleanly stated by the development team to the management so that they planned for some "curing" phase. And the management — they should probably have some objective metrics that will show them — unless they can "feel" it — that this kind of situation has arisen.
Mar 31, 2011
Make it run, make it right
The practice of first making things run and then proceeding to making them right in software development is something I've always been adhering to — at least for each particular "atomic" task. Advantages are numerous: you get a proof that something is possible and/or understanding how hard technically that is, you and your customer (or analyst or PM or whoever is interested) can see the result and change things until it's too late, and the risk of not doing the task on time is reduced.
However, it still leaves a lot of room for choice for the developer: suppose you have an iteration during which you are planning to do 10 features. What will your best strategy be: trying to make each feature in its entirety by first making it run and then refactoring it to the point where you consider it to be right? Or rather make all 10 run first then refactor? Choosing somewhere between?
Each of the strategies has its good parts and its downsides. If you are doing everything run, the customer may ponder a feature, get some UX on it and come back with a change later until you started refactoring it. You also start refactoring with more requirements in mind and can make more accurate decisions. On the down side, if no time is left for refactoring you are left with a pile of hacks; and while making things run this piling up of hacks can also slow you down substantially: you don't have right abstractions. Interaction with other developers is also substantially hindered as you are not communicating your intentions clearly to them. And there's also a risk of the customer starting to seek perfection and drown you in changes until you get a chance to refactor.
Downsides of this approach are clearly bright sides of the contrary one and vice versa. If you don't get your features done during the iteration, they are likely to be moved to the next one. Release date may be shifted further and further and the product is put on risk.
So as the bottom line I'd say this: if your customer wants to have something that can be used, promoted etc. while the next version is being developed, be it with some warts and errors and things not perfect, and if both you and the customer understand that the first version will not be supported and is likely to be more thrown away than refactored, and if the whole thing is not so monstrous that it will start falling apart until you are finished (either because things get tangled for yourself even or for lack of communication in the team of developers) then you are probably better off with the "make ALL run, then make it right".
However, it still leaves a lot of room for choice for the developer: suppose you have an iteration during which you are planning to do 10 features. What will your best strategy be: trying to make each feature in its entirety by first making it run and then refactoring it to the point where you consider it to be right? Or rather make all 10 run first then refactor? Choosing somewhere between?
Each of the strategies has its good parts and its downsides. If you are doing everything run, the customer may ponder a feature, get some UX on it and come back with a change later until you started refactoring it. You also start refactoring with more requirements in mind and can make more accurate decisions. On the down side, if no time is left for refactoring you are left with a pile of hacks; and while making things run this piling up of hacks can also slow you down substantially: you don't have right abstractions. Interaction with other developers is also substantially hindered as you are not communicating your intentions clearly to them. And there's also a risk of the customer starting to seek perfection and drown you in changes until you get a chance to refactor.
Downsides of this approach are clearly bright sides of the contrary one and vice versa. If you don't get your features done during the iteration, they are likely to be moved to the next one. Release date may be shifted further and further and the product is put on risk.
So as the bottom line I'd say this: if your customer wants to have something that can be used, promoted etc. while the next version is being developed, be it with some warts and errors and things not perfect, and if both you and the customer understand that the first version will not be supported and is likely to be more thrown away than refactored, and if the whole thing is not so monstrous that it will start falling apart until you are finished (either because things get tangled for yourself even or for lack of communication in the team of developers) then you are probably better off with the "make ALL run, then make it right".
Ярлыки:
agile
Subscribe to:
Posts (Atom)