пятница, 25 мая 2012 г.

Risen2: Dark waters

Excellent Voodoo implementation. Ability to move into several main story characters and control them as you please.

Excellent way of experience implementation in the form of Glory like Gold which you can spend whenever you want.

Excellent decrease of damage by improving your ability with constant health instead of unrealistic health increase.

Excellent Underworld inversion.

Excellent monkey taming instead of magical transformation into an insect: more realistic.

When I was talking to Sebastiano's daughter in Sword Coast she gave me the knife to get leopard or other puma skin to make fashionable clothes. Since I killed that leopard before I got the knife, when knife was given, I've
also received leopard skin. That's good, because in Gothic you should have first got knife (and/or talent) and only then could get the skin. If you killed animals and only later learnt the skill, those things are lost. Here, they're not.

Bad thing about Mauregato in Caldera that you first MUST see Mauregato's incriminating papers, and only then go to the Library, otherwise you won't get Garcia's location.

Excellent solution for quick saves on F5 - they are saved as different files. This saves from going to Save menu.

The bad part of Risen2 saves is that they are still very big, about 6MB each. With a lot of saving, it takes a lot of space. Consider Mass Effect where each save takes only several KB.

суббота, 28 апреля 2012 г.

Complexity Conservation Law

Complexity Conservation Law

Complexity Conservation Law

Translation by Michael Kapelko (kornerr AT GoogleMail)
20120428



Original article by Igor Tkachev in Russian: http://rsdn.ru/article/philosophy/Complexity.xml

Forward

It is a simple task to make things complex, but a complex task to make them simple.
-- Meyer's Law

There are many practices, concepts, patterns and other scary words we use everyday in our professional lives, but often blindly, without even wondering why we do it. Why are those things necessary, are they good or bad, when are they good or bad? Why do we need all these concepts? The answer is obvious. In the end, it all exists to help us fight software development complexity. Now it's time to question ourselves - what is complexity and how can knowing what complexity is help us to better understand and use the concepts that exist to fight complexity?

It's a bit hard to answer that question. Complexity is a versatile concept, contradictory at times. In short, complexity can be defined as a measure of efforts necessary to solve a problem. When working with code, we usually have the following types of complexity:

  • quantitative complexity (many characters);
  • code perception complexity;
  • code alteration (flexibility) complexity;
  • algorithmic or intellectual complexity, roughly speaking, how smart the person solving a problem is;
  • structural complexity - application architecture complexity;
  • learning complexity or entry threshold - minimal level of skill and knowledge necessary to understand certain solution of a problem;
  • problem understanding complexity.

What makes it even harder is that all these types of complexity are interdependent and have no strict boundaries. Complexity itself can be either objective or subjective to make someone's life harder. Fortunately, we're not interested in subjective complexity; our aim is objective complexity. How does one fight objective complexity? In my opinion, the main problem is that there's no way to completely remove objective complexity. We can decrease, increase, divide and multiply complexity; we can create it out of nothing, especially to complicate someone's life, but it cannot be removed completely. We can transform complexity into other kinds, optimize it, rearrange it, and, in the end, get it under control. Virtually all concepts of software development strive to achieve that purpose - transform complexity, optimize efforts to solve a problem. By transforming complexity, we get an opportunity to better handle it and, in consequence, better control the code we develop. This is, in essence, our main purpose - we must control the code, not let the code control us.

Complexity transformation is essentially one simple thing - by removing complexity from one place, it is always added somewhere else. If this doesn't happen, most likely we can't see or understand it yet. Complexity never leaves without a trail - it transforms itself into other kinds of complexity. Let's call it complexity conservation law.

Remark

To prevent misunderstanding, the author wants to calm those that understand the article literally. The author acknowledges he didn't discover a new nature law. Moreover, he understands that strictly scientifically speaking no such law exists. The choice to name the article that way is stipulated by the author's liking for pompous and provocative titles. That's why there's no need to look for formal definitions and proofs in the article. The article's purpose is to classify complexity types, better explain their nature, unforeseen consequences, and their influence on code development.

Complexity conservation law leads to a simple conclusion - there's no ideal way to fight complexity. It's impossible to apply a concept or pattern and only decrease complexity. We always sacrifice something. With that knowledge, we can pretty accurately measure the ratio of what we spend and what we receive. Based on that, we can decide if it's reasonable to apply this or that solution in each case.

Let's have a look at each type of complexity.

Quantitative complexity

This is a case that involves a lot of written code in order to solve a problem. If most of this code is of the same kind, we can fight such complexity with the code reuse concept. Sometimes it helps a lot, sometimes only a tiny bit. For the user, code reuse decreases quantitative complexity, code perception complexity, code alteration complexity, and algorithmic complexity, but increases learning complexity. For the writer, it increases practically all types of complexity.

When is it not helpful? It doesn't help much when we try to encapsulate the code for reuse beforehand. It can be reused, but it happens not to be needed in practice. We have added complexity into the problem solution, but gained nothing. It also doesn't help much when the author doesn't have enough skill and/or brains. It's no secret that one needs a certain skill level to develop libraries and reused components. If one does it without thinking, such code won't be used by anybody, at best. At worst, it will complicate both perception and flexibility everywhere it's used.

On the other hand, high quality sets of reused components (libraries) can significantly decrease complexity. Take, for example, the System.String class. It is easy to use and is self-sufficient. All string handling complexities have been shifted from our hands into those of Microsoft developers and thousands of servers testing the class efficiency in all possible versions and configurations 24/7. It's a complexity decrease for us, often for free, but not necessarily 100% free.

This concerns almost all the tools we use to solve problems. Modern operating systems, frameworks, libraries, development environments, programming languages - development of all this is aimed at shifting as much complexity as possible from us into these tools. Sometimes we pay for it with money and always with increased learning complexity, but the cost is worth the quality of the tools.

Perception complexity

This type of complexity is mostly about code formatting, not its contents. It's pretty easy. Open up any chunk of code and note the time you need to understand how it operates. Perception complexity depends on many factors: code style, following naming conventions, algorithm clarity/confusion, used tools' expressiveness, development environment including code highlighting and navigation, etc. Also, perception complexity has a direct relationship with algorithmic complexity and entry threshold.

To avoid confusion with other complexity types, you can imagine that you are left without your favourite Visual Studio, IDEA or any other Eclipse, and you have to edit foreign, badly formatted, incosistent with any naming convention code in Notepad. Also, with all monospace fonts absent and half of tabs replaced with spaces. Did you imagine it? It’s horrible!

Alteration complexity

Simplicity of code perception does not mean simplicity of code alteration. Of course, simple code is easy to change, but the main property of code alteration complexity is its flexibility. Simple code is not always flexible, and flexible code is not always simple. This, again, proves that complexity cannot be reduced, it can only be transformed. Many practices and patterns exist to increase code flexibility; consequently, they usually increase both perception and learning complexities. Let's take any pattern of such kind, say, IoC or Visitor. Some IoC implementations introduce additional entities to the code, make the algorithm less obvious and increase perception complexity - particularly, the navigation through it. Visitor divides a whole hierarchy structure processing algorithm into many pieces which, in turn, significantly increase perception complexity. This always happens. Something removed here results into another thing added elsewhere. Is it worth to strive for total code flexibility then? It has to be decided on a case by case basis. Sometimes we gain significantly and enforce code control, and other times we only introduce additional complexity to code without gaining anything and completely losing control over it. It's important to remember that, according to the deduced law, any pattern is at the same time an anti-pattern, so you should consider both positive and negative effects of pattern application. In some cases the most beautiful pattern can cause more harm than good.

Algorithmic complexity

In short, algorithmic or intellectual complexity is the minimal necessary level of intellect one needs to solve a problem. Particularly, it is the ability to hold a problem in one's head as a whole. Frequently this complexity is confused with learning, knowledge level, but it's different. Programming itself presumes having a certain amount of brains already, but it's no secret that different people use different level of brain activity to solve the same problem. This isn't the most important thing. In fact, in life there aren't many algorithms a simple mortal can't grasp. The most important thing is that algorithmic complexity is easily increased in magnitudes by small code manipulations, usually by mixing different algorithms' implementations in one place. Suppose we have an input stream of data, output stream of data, and data processing algorithm. Let's see how much this may cost.

Suppose we parse XML, process it a bit, and produce HTML. The algorithm of input stream parsing is pretty simple and has an intellectual complexity of, say, 3 units, data processing - 4 units, HTML output - 2 units. Suppose mixing it results in 3 * 4 * 2 = 24 units of complexity. Suppose our intellectual limit equals to 100 units. Thus, we have easily solved the problem with only a little of brain activity. Now, suppose we're writing a compiler, and at some place we mix text parsing, executable code generation, and some optimizations. These algorithms are obviously more complex than those of an XML example. Let's value each of them as 10 units; this results into 10 * 10 * 10 = 1000 units of complexity, i.e., it exceeds our intellectual limit by a factor of 10.

Obviously, everything happens with different formulas and units in life, but you should get the idea. The more complex the algorithm and the bigger the mix of them in one place, the faster the problem algorithmic complexity grows and the faster we lose control over it.

Let's take a look at Single Responsibility Principle (SRP).

Remark

I take examples where good and correct practices intentionally look not as good. It's not a way to diminish them, it's a way to get a better understanding of their core, looking closer at their not so obvious properties.

And now, SRP. SRP is the principle that allows to control algorithmic complexity with the help of decomposition. The principle dictates to divide algorithm into units, each of which does its own job. Thus, complexity of a problem is no longer a multiplication, but a sum, and most importantly the algorithmic complexity of each unit stays at its starting level. This way we don't need to handle an algorithm with the complexity of 1000 units, but 3 algorithms with complexity of 10 units each. What is so bad about this? Let's recall the complexity conservation law. SRP does not only decrease the algorithmic complexity of the code, but it also increases perception complexity, introduces quantitative complexity and, in some way, decreases flexibility. For the compiler example, such a trade will be well worth it because the introduced complexity is hardly seen through a microscope, compared to the rest of the compiler code. But what happens if we apply the principle for XML to HTML code example? First of all, we would have to introduce intermediate data structure (like AST for our compiler) and place the 3 algorithms into different methods or even classes. To combine all this, we would also have to add some sort of coordinating code. Our initial algorithm took about a hundred simple lines; now we can get 3, 4, or even 5 hundred lines placed in different modules. Will the gain be adequate to the introduced complexity? The answer is obvious.

One may think that such principles have to be used only in complex systems where SRP gives a lot of benefits. But the problem is that SRP dictates to divide a complex thing into several simpler ones, which are not guaranteed to be simple enough and might need further SRP application. When do we stop? We have to decide using a case by case basis. If you ask me, I do the following: if I can't understand the necessity at the moment, I prefer to postpone the SRP application until I can't hold a problem as a whole in my head and feel discomfort. If you feel the same, then stop and refactor.

Remark

Digression for managers.

When your programmers tell you they need time to refactor the code, it doesn't mean they are stupid, short-sighted or trying to waste time surfing the Internet. If time has come to refactor the code, it must be refactored. Why not do it right at the beginning? Because we might introduce unnecessary complexity without being sure that we will gain anything. Also, a more complex code requires more time working, and nobody guarantees your project would be at the stage it is now. The purpose of refactoring is to decrease and transform complexity, to find out and remove problematic ideas. This results in a better control over the code and its complexity.

Besides decomposition, algorithmic complexity can be controlled with the help of additional abstraction levels. If we imagine decomposition as a tool that allows us to cut a problem vertically by functions, abstraction arranges additional levels in layers to the logic, hiding implementation details of the previous layers. Thus, by abstracting from details immaterial to the new abstraction level, we free ourselves up to new things. But do not overdo this. As you know, any problem can be solved by introducing an additional abstraction level except the problem of having too many abstraction levels.

The third and least effective way to fight intellectual complexity is by being "in the zone". If you would think hard and long enough about a problem solution, in the end, you will build its adequate model with all nuances which you can put as a whole into your grey matter and solve it more or less successfully. I'm almost sure any problem can be solved this way. At this point, however, I recall the following phrase: "Anybody can be an academician, but while one needs 30 years for that, another needs 300". Besides, there's yet another defect of this method: as a rule, after solving a problem, the grey matter tries to get rid of the scare that filled it during solution time, and with time transforms a strict problem model into an area of vague doubts. The second approach to the problem requires almost the same amount of time to go into the zone, and nobody guarantees the new model will be identical to the previous one.

A note on optimizations. Most optimizations introduce an increase in quantitative and algorithmic complexities (sometimes in magnitudes) and a decrease in flexibility, converting one simple algorithm into a badly readable mix of two algorithms - the initial one and the optimization one. If the benefits are barely visible, it is better not to do it. However, it's not always obvious. Fortunately, declarative optimization ways start to appear nowadays which solve a problem leaving the initial code almost untouched. For example, PLinq and its AsParallel method, Nemerle / BLToolkit result caching attributes of called methods, etc. can be attributed to such an optimization. I think that the number of such tools (and their positive effect) will grow in the future. Nonetheless, it's important to understand now that the main problem of optimization is the algorithmic complexity's increase due to the mix of different algorithms in one place. Our task is to minimize any negative outcomes of such a mix.

Structural complexity

I think it's pretty logical to divide a code into two kinds: the one inside the methods and the one outside them. The one inside is algorithms + the control code. The one outside is grouping algorithms into modules, components, classes and other structuring. If you have difficulties changing your code, you should understand where the problem is located - inside the methods or outside them. Oddly enough, the problem is usually located in grouping, and thus refactoring should be started in there. Algorithms are easy to deal with: they either work as good as expected, not so good, or not at all. Not everything is obvious with algorithms' grouping. It's all about strong coupling, weak coupling, and a number of corresponding patterns and practices. Unfortunately, the terms of reference and functional requirements do not define the code structuring rules (except the cases where structuring is part of a task). As a result, grouping becomes a problem to solve the programmer's problems, i.e., it becomes a code support problem. Code support problems are code flexibility problems, difficulty of their change. We group codes into modules and classes for easier management, modification and extension. In complex systems, code grouping and competent organization are key to reach its acceptable flexibility. The more complex the system, the more attention should be paid to code grouping and structuring.

Structural complexity is tightly coupled with algorithmic one, and is often both the means to decrease it and increase it. SRP example illustrates this clearly. In the above examples, it's clear when to apply SRP and when not to. But it's not all that simple in reality. The verge between "when to apply" and "when not to" is often so unsteady, that there's only room for intuition and preferences. But, as we know, logic ends where preferences begin. Luckily, the rule works the opposite way as well. Sometimes neither logic nor intuition works, and the most highly acknowledged patterns and practices lead to code complexity increase. It's called over-architecture in programming which happens nearly as frequently as total absence of architecture. Actually, when you're in a difficult situation and you don't know what to decide, it's not that hard to find out the usefulness of a tool. We already know it brings additional complexity into the code. The only thing left is to ask yourself, or the one who insists on using it, what problems it solves and what benefits we gain. Often that's the only question you need to ask yourself to make the right choice.

Learning complexity

This might be the most non-obvious type of complexity as it relates to code indirectly, depending on the man who develops it. In other words, the same code can be both easy and difficult for different men. Knowledge of programming paradigms and the ability to use modern tools allow us to decrease all complexities by increasing the entry threshold and transforming complexity parts into used tools. This, in turn, allows us to significantly simplify the code and to solve more complex problems, and the other way around. We can solve a problem using primitive and outdated tools also, but the solution might be more complex for perception, take more space, and be less flexible.

But is this all that simple, does a high level of knowledge always lead to benefits? If you apply knowledge not just to apply it, but to solve a problem, as a rule, the result is beneficial. Only those members of the team lose for whom the necessary entry threshold is yet unreachable.

Often some managers try to minimize risks by maintaining quite a low knowledge level of the team. This allows for easier replacement of an unskilled person by another unskilled person. It's not hard to conclude, according to the complexity conservation law, all complexities of applications developed in such teams are located in their code. As a rule, there is a lot of such code; it is not flexible, hardly readable, and is of a great algorithmic complexity which is frequently high above the accessible team member level. The result is also quite predictable - delays of releases, budget excesses, project failures. How do we fight it? We must teach people by transferring the complexity of the code into their heads and used tools to make a balance between manager risks and complexity control. It is vital to always remember that a primitive brain won't solve a complex problem.

Problem understanding complexity

Obviously, before you can solve a problem, you have to understand it. Moreover, while the relationship between problem understanding and problem solving is quite evident, understanding and solving complexities has no relation at all. Often a problem's definition is simple, but the solution is complex, or vice versa. Having knowledge of a problem area or having a previous experience in solving similar problems, qualitative terms of reference significantly decrease the problem understanding complexity. On the other hand, outdated documentation can increase one's understanding complexity.

The simplest way to fight the understanding complexity in big projects is to have a specially trained person (an architect or analyst) who delves into all of the details of a problem and translates said details into a language that different developers can understand. The developers, in turn, can concentrate on technical details without needing to know everything about the system being developed. Such an approach is pretty reasonable, but the business becomes vulnerable if important knowledge is bound to only one or two persons.

Another widespread way to fight the understanding complexity is to postpone the time when you get to understand a problem until a better time. I.e., we start to solve a problem here and now, having only general understanding of the problem. Detailed understanding of what kind of problem we solve will come later, almost at the time we finish it. XP and Agile are of this approach. They allow the developer to control chaos in a problem statement. This approach is characterized by a higher code flexibility requirements. In fact, flexibility is the fundamental requirement in this case.

Note that this type of complexity is tightly coupled with learning complexity. In the end, the only difference between them is probably that problem understanding complexity is related to the subject area and learning one is related to the used tools.

Instead of conclusion

It would be a lot easier if we could find a way to measure complexity quantitatively, but, I'm afraid, it's impossible. I was intentionally escaping any measurement hints (except for abstract units) because I think it's impossible to compare quantitatively the perception complexity of an awfully formatted code, algorithmic code complexity, code size, learning complexity necessary to understand it, and problem understanding complexity. I guess one can find suitable measurements for each type of complexity separately, and even express them as a function of time which allows it to summarize different types of complexities. However, each of the complexities alone is not of great interest, because they don't allow you to see the big picture. So far we can only operate in "less, more, a lot, and small" terms, but it is often enough. In the end, our purpose is not to measure units, but to keep the code under control. The complexity conservation law helps us understand that any tool may be used with either positive or negative effects. In practice, you should be critical to absolutely any pattern or concept. Even to such well known things as decomposition, grouping or abstraction, because in 100% of cases they always increase code complexity; you have to perspire a lot to decrease it. In fact, you would be better off looking at used tools through a prism of complexity, and not the other way around. If you would take the concept that complexity control in software development is primary, and all the rest is secondary as your rule, most of the used practices become more clear and visible.

For the conclusion, it is worth mentioning that complexity accumulates itself. One time we didn't format the code here, another time we didn't follow the guidelines there, overused SRP or other patterns a bit, or underused it. First, the code grows, then it becomes less readable and flexible, then additional algorithmic or structural complexity is introduced unreasonably, and as a result, we start to lose control over the code. If you don't want this to happen, you have to always, at every development stage, fight excessive complexity; seek and remove it and strive for the simplest solution. Unfortunately, we can't always do that because of one simple fact. As you all know, the most complex thing in the world is simplicity.

I guess that's it. Comments, additions, refutations, and exposures are welcome.

понедельник, 25 октября 2010 г.

Работа 2.0. Программист, который отвлекается

Перевод статьи бывшего лидера проекта OGRE Стива Стритинга под названием "Работа 2.0. Программист, который отвлекается" (Work 2.0 - The interruptible programmer).
Оригинал: http://www.stevestreeting.com/2010/09/04/work-2-0/

Мне 37, я (профессиональный) разработчик уже 16 лет. Вы можете подумать, что за всё это время я выработал эффективный стиль работы, который бы приводил к желаемым результатам (меньше кода, поставка программ в срок и пр.) без выбивающих из колеи ситуаций, но, к сожалению, это не так. Думаю, стиль, который я практиковал первые 15 лет своей карьеры, присущ многим разработчикам-энтузиастам: трата тонн часов. 12-16-часовые дни, марафоны программирования по вечерам и выходным, пицца на клавиатуре, тяжёлые периоды, отладка в 3 часа ночи, когда не можешь пойти спать, т.к. чувствуешь причину ошибки в двух шагах, чёрт подери, отчаянный спринт до дедлайна (deadline), когда удаётся заделать брешь как раз перед тем, как мир проваливается к чертям. Если всё это вам хорошо знакомо, вы мудро киваете головой, возможно, даже немного ухмыляетесь, вспоминая прошлые испытания и славу. Такой сумасшедшей самоотверженностью восхищаются в наших кругах и часто ожидают от любого уважающего себя разработчика.

Но оказывается, что такое положение дел вредит здоровью - кто бы знал? Те из вас, с кем мы знакомы либо следит за моим блогом, знают, что меня силком выдернули из такого ритма из-за проблем со спиной, которые я поначалу игнорировал, затем создавал видимость решения, но в итоге был вынужден уступить. Работая на самого себя, это было главной сложностью. Выползание из ямы, которую я вырыл себе, заняло много времени и принесло много разочарования. Я прочитал разные книги о повышении продуктивности работы, чтобы иметь возможность работать дальше. В итоге оказалось, что лучшие ответы - это те, которые ты формулируешь для себя сам. Я хочу поделиться некоторыми из них.

Но я "в зоне"!

Итак, я хочу поговорить о самой большой проблеме, с которой столкнулся: период концентрации. Теперь я не могу безвылазно сидеть за столом более часа. Если я не встану, не пройдусь и не разомнусь немного хотя бы раз в час, то вставать позже будет намного больнее. Наверно, следующие несколько дней тоже. Теперь я не могу работать более 8 часов в день без появления боли. Проблема в том, что, как программист, за последние 15+ лет я выработал стиль работы, при котором я постепенно "погружаюсь в зону" и программирую очень долго за раз без перерыва. Это частая картина среди программистов, мы любим закрыться от внешнего мира, одев наушники, чтобы не отвлекаться и т.д.. В этом также причина того, почему мы имеем склонность плохо реагировать, когда нас прерывают. Программирование требует концентрации, и кажется, что концентрация работает как ламповая система: много времени занимает разогрев системы, а когда она запущена, не хочется её останавливать, т.к. запустить её ещё раз будет сложно.

Я думал, нет способа это исправить и начал примиряться с тем, что из-за этого я менее продуктивен. Тем не менее, за последние полгода я обнаружил, что эта проблема совсем не неподатливая, наоборот, подход "медленный старт, долгий непрерывный сфокусированный процесс" в большей степени является выработанным поведением, а поэтому можно переучить себя работать иначе. Это немного походит на то, как некоторые люди учатся использовать многофазный шаблон сна. Никто не говорит, что этого нельзя сделать. Просто когда привык делать что-то одним способом, менять это поведение сначала очень-очень трудно. Это возможно, если у вас хватит сил и терпения.

Итак, моей целью было привыкнуть к большому количеству небольших занятий работой в течение дня вместо малого количества больших кусков работы без снижения уровня производительности. Для этого нужно было найти способ возврата "в зону" за короткое время. Во многом так же, как те, кто практикует многофазный сон, добиваются скорого прихода фазы быстрого (REM) сна. У меня это уже почти получилось или, по крайней мере, у меня это получается намного лучше, чем раньше. Итак, что я делал для перехода на новую схему?

1. Примите перерывы.

Это не столько техника, сколько взвешенная психологическая установка, которая является сутью всех описанных мною далее подходов. Вместо того, чтобы быть программистом, избегающим перерывов любой ценой, вам нужно их принять и научиться ими лучше управлять. Это сложно: вам придётся отвергнуть годы сопротивления им. Сначала, пока не привыкните, будет чувство, что не всё успеваете сделать. Многие сдадутся на этом этапе, если только не будет достаточно мотивации для продолжения. Для меня это была ежедневная боль в спине. Суть в том, что переход в такое состояние - это лишь фаза, и можно быть программистом, который отвлекается и по-прежнему успевает всё в срок. Но вы должны научиться не бороться с перерывами, к чему и призывает первый пункт.

2. Всегда храните контекст вне головы.

Перерывы вызывают много проблем, т.к. из-за них теряется контекст. Когда вы "в зоне", вы жонглируете огромной частью контекста в голове, регулируя её на лету, постоянно поддерживая и настраивая взаимосвязи между проблемами. Перерыв заставляет вас всё бросить, а подобрать это обратно занимает много времени. Для решения этой проблемы я решил расположить как можно большую часть контекста на внешних носителях:

2.1. Записывайте все свои мысли о текущей задаче.

Я сам себе летописец. Я всегда помечаю, что я делаю, даже если это добавление комментария к обсуждению, часто фиксирую небольшие изменения в хранилище и пишу подробный комментарий к этим изменениям (вы пользуетесь распределённой системой контроля версий, чтобы частые фиксирования небольших изменений были удобны, да?) или просто делаю запись на клочке бумаги. На самом деле, это совсем не обременительно, наоборот, запись мыслей часто помогает лучше понять проблему. Грубо говоря, каждые 30 минут я создаю некоторую новую часть контекста, которую сохраняю где-либо вне головы. В противном случае большая часть проблем будет связана именно с воссозданием контекста в голове, если меня прервут. Запись не занимает много времени и имеет другие преимущества, например, история процесса размышлений.

2.2. Беспощадно игнорируйте косвенные задачи.

Вы, наверно, заметили, что в предыдущем пункте я использовал словосочетание "текущая задача", единственное число. Не "задачи". Не существует такой вещи, как "несколько текущих задач". Есть лишь одна текущая задача, над которой вы работаете, и отвлечения.
Вероятно, мы все используем системы отслеживания ошибок / управления задачами (bug / task trackers), но, когда работаешь над задачей, очень часто можно заметить новую ошибку, улучшение текущего кода или просто придумать новый крутой функционал. Сколькие из нас сразу же принимаются за решение этих косвенных задач, т.к. мы оказались в этой области кода, это "тривиально" или просто круто и хочется это сделать? Раньше я поступал именно так, но теперь иначе: любые косвенные задачи, не относящиеся прямо к тому, чем я сейчас занят, я записываю в систему управления задачами и сразу же забываю, пока не завершу текущую задачу, независимо от их размера, уместности и срочности. Это звучит просто и очевидно, это даже может быть официально закреплено у вас в организации, но я сомневаюсь, что большинство программистов всегда так поступают. Это выгодно, потому что даже малейшее отвлечение добавляет дополнительный уровень контекста, который нужно держать в уме, который опять же сложно собрать обратно, когда вас отвлекут. Чтобы такой подход работал, нужна быстрая и лёгкая система управления задачами, не требующая дотошного описания новой задачи. Нужно успеть за 30 секунд записать новую задачу, выгрузить новую мысль из головы без отвлечения от текущей задачи. Подробности реализации можно будет указать позже.

2.3. Всегда знайте, чем будете заниматься далее.

Этот пункт из GTD ("Следующие действия"). По возвращении к работе после перерыва вы не должны тратить время на выяснение, что же делать далее. Поможет вам в этом система управления задачами и комментарии к текущей задаче. Если вы были вынуждены заняться другим своим проектом и хранили контекст по нему вне головы, не составит труда понять, какое действие нужно делать далее по проекту. Важно иметь одно следующее действие по каждому из проектов. Если действий несколько, придётся тратить время на выбор между ними, а это потерянное время (см. следующий пункт про очерёдность). В каждый момент времени вы не только должны иметь одну текущую задачу, но и одно недвусмысленное следующее действие по этой задаче. Половина успеха эффективности работы состоит в знании следующего шага.

3. Упорядочивайте от противного.

Я упомянул следующие действия в предыдущем пункте, но как определить их очерёдность? Много времени может быть растрачено на выяснение очерёдности, и я искал способ его уменьшить. Раньше я планировал, исходя из того, что хочу выполнить всё перечисленное в списке; я просто пытался понять, какую из задач мне нужно сделать первой. Я обнаружил, что можно сократить время планирования, а также получить более хорошую и менее амбициозную очерёдность путём изменения порядка принятия решений: предположить, что я не сделаю ни одну задачу, и оценить негативные последствия невыполнения каждой из них. Так что вопрос "Какая из возможностей А или Б более важна?" превращается в "Предположим, мы выпускаем продукт без возможностей А и Б. К чему приведёт отсутствие каждой из них?". Может показаться, что разница между ними несущественна, но из своего опыта могу сказать, что оправдание реализации функционала приводит к более реалистичным оценкам, нежели попытки установить относительную очерёдность реализации, предполагая выполнение всего списка.

4. Осознайте выгоды перерывов.

Большая часть вышеизложенного касается минимизации негативных последствий перерывов, но правда такова, что они тоже полезны для работы. Держу пари, все программисты задерживались допоздна на работе, пытаясь исправить ошибку, решение которой находили либо на следующий день за 15 минут, либо в каком-либо малообещающем месте вроде душа. Это очень просто объяснить: длительные периоды концентрации кажутся продуктивными и даже могут быть таковыми для оперативного / последовательного мышления, но для всего остального вроде творческого мышления и решения задач очень часто результат прямо противоположный. Проблема не только в утомлённом мозге, который соображает менее чётко, но и в том, что решение задачи часто находится не там, где мы завязли на несколько часов, а в совершенно иной плоскости. Длительные периоды концентрации имеют тенденцию "запирать" движение мысли по одной колее, что препятствует появлению вдохновения и озарения. Творчество всегда происходит, когда вы не стараетесь. Это часто недооценённый, но жизненно важный инструмент в программировании.
Перерыв в этом движении по одной колее может оказаться очень полезным.

Я мог бы ещё добавить советов, но, думаю, пока достаточно. Надеюсь, перечисленные выше вам помогут.




Примечания переводчика

Эту статью я решил написать после прочтения книги Гранина Д. А. "Эта странная жизнь", рассказывающая о Любищеве А. А., который на протяжении 56 лет вёл учёт своего времени на жизнь. Советы Стива отчасти соответствуют подходам Любищева. Например, Любищев выучил Английский язык во время поездок в транспорте. Т.е. использовал много маленьких кусков времени.

На перевод статьи я затратил 18 календарных дней. Из них на первоначальный перевод ушло 4ч 20м, на ревизию 4ч 10м, на публикацию 1ч 5м, т.е. всего я потратил 9ч 35м своей жизни. Таким образом, я использовал много небольших кусков времени.
Хочу отметить, что использование 10- и 15-минуток довалось намного легче. Сейчас публикацию я сделал почти за один присест и чувствую утомление. Чувствую, что уже надоело заниматься этим делом. Так что короткие периоды работы ещё полезны и для сохранения бодрости духа.

Также очень интересно получилось, что не только я перевёл эту статью на Русский язык. То же сделали в этом же месяце ещё два человека, опубликовавшие свои переводы на Хабре: http://habrahabr.ru/blogs/arbeit/106523/ и http://habrahabr.ru/blogs/arbeit/106510/.

Выражаю благодарность Kai SD за указание трудночитаемых предложений. Которые смог - исправил. Некоторые позаимствовал у raacer, который сделал перевод по второй ссылке.

понедельник, 30 августа 2010 г.

Косячный штраф

Скоро у нас в отделе ПО введут штрафы за косяки.
У меня косяки случаются регулярно. В основном, из-за того, что возможности тестирования сильно ограничены или вообще отсутствуют, поэтому приходится проверять на живых абонентах. Мне ещё повезло, что от меня обычно страдают физлица, а не юрлица. Я знаю, что косяков у меня ещё будет много, поэтому данное нововведение меня огорчает.
Да и каждый мало-мальски критичный к себе человек знает, что не совершает ошибок лишь тот, кто ничего не делает.

Первый раз с таким предложением испольнительный директор Рома подошёл к нам, когда я положил около четырёх районов города тем, что неверно изменил запрос SQL для выдачи аренд DHCP. Он дал задание создать регламент в основе сводящийся к тому, что если ты накосячил и от тебя пострадали многие, то тебе не поздоровится.

В прошлую пятницу "накосячил" коллега тем, что выполнил требования начальника другого отдела, который прибежал и сказал, что нужно быстро-быстро выключить тех юрлиц, которых включил его сотрудник по ошибке. Быстро-быстро и вырубили. Оказалось, что вырубили слишком много. Виноватыми, как всегда, назначили исполнителей. Может, заказчикам тоже не повезло. История об этом умалчивает.

Рома пришёл сегодня в понедельник и сказал, что за "немного тронуть базу" 5 тысяч, за сильно - 10. Так он был рассержен, когда ему сказал много приятного кто-то из тех самых юрлиц. Вообщем, его настрой можно понять.

Меня огорчает именно то, что в данном случае Рома не хочет решать проблему, а ищет виноватых. В данном случае все себя чувствуют плохо - и исполнители, и заказчики. Решением проблемы могло бы стать выяснение, почему сотрудник решил включить тех юрлиц, которых включать не надо было. Можно сделать выговор, но ведь главное, чтобы такого больше не повторялось.

В книге "Pragmatic programmer" я нашёл очень уместную вещь по этому поводу. Там говорится, что всё программное обеспечение должно снабжаться тестами, которые нужно прогонять после каждого изменения программы, дабы найти возможные появившиеся ошибки. Но не всё возможно протестировать. Не все ситуации возможно предусмотреть. В конце концов, глаз может просто замылиться. Поэтому если обнаруживается какая-либо новая ошибка, то она должна добавляться в эти самые тесты для проверки при последующих тестированиях. Лишь в данном случае она никогда не повторится больше, т.к. будет учтена.

Наказания в данном случае бесполезны. Всё, к чему они приводят, - это ненависть работника к работодателю.
В случае коллеги, ненависть других работников, которые видят несправедливое отношение к собрату со стороны работодателя.
В случае со мной, моя ненависть, т.к. наказание будет за мою работу, которая как раз заключается в решении непредвиденных проблем, которые возникают в ходе внедрения новых технологий.
По такой логике нужно наказывать начальников, которые инициируют все проблемы на работе.

Итог: надо решать проблемы, а не искать виноватых.

воскресенье, 23 мая 2010 г.

Настоящие танцы, или почему я всегда ненавидел школьные/вузовские дискотеки и почему я до сих пор ненавижу обычные ночные клубы.

Понял я это 23-го мая 2010-го года после семи часов вечера, когда пришёл в клуб, где состоялась дискотека в ритмах Сальсы, Бачаты, Танго и ещё чего-то латиноамериканского. Когда я увидел настоящие танцы, я вспомнил то "месево" в школах/вузах/обычных клубах.
В латиноамериканских танцах участвуют партнёр и партнёрша. Они не тупо прыгают на ногах, машут головами, они вообще ничего тупого не делают. Они выполняют определённые "комбинации".

Т.к. в танцах участвует пара людей, то они объединяются в ритме. Они всё время контактируют. Объединение, раз. Тактильные ощущения, два.
Если кто не знает, то всем нам необходимы объятия. Маленькие дети, например, без объятий умирают. Объятия необходимы для чувства безопасности. Для того, чтобы не чувствовать себя одинокими. Это одни из базовых потребностей человека, без удовлетворения которых у каждого заводятся свои тараканы в голове.

Ведёт партнёр. Мужчина главный, женщина следует. Это соответствует ролям мужчины и женщины, заложенным природой. Нет всякой эмансипаций и прочего "телевизера". Мужчина получает власть, а женщина чувствует силу мужчины. Верная постановка ролей, нет чувства дискомфорта, три.

Что мы имеем в обычных клубах? Тупое подражание танцам.
Люди в основном дёргаются разрозненно. Иногда трутся друг о друга по принципу "как получится". Разделение, раз.
Нет чётких ролей, кто ведёт. Мужчина не чувствует власть, женщина не чувствует силу. Не удовлетворяются базовые потребности. Отсутствует всякая иерархия и всякие правила, два.

После двух часов дискотеки у меня возник вопрос: "Почему детей не учат настоящим танцам?" Почему вообще в мире так мало показывают настоящего, ценного, нужного?

Рекомендую к прочтению отличную статью "Издержки эмансипации".
У себя размещу лишь её начало, отрывок из произведения Е. Евтушенко:

Как получиться в жизни так могло?
Забыв про смысл ее первопричинный,
Мы женщину сместили. Мы ее
Унизили до равенства с мужчиной...

четверг, 11 марта 2010 г.

Не ломайте жизнь детям переездами

Конец 2008-го года, город Кемерово. В эти дни я убивал время в локальном пиринговом чате (хаб YeOlde). В один прекрасный день там появилась необычная девушка, как в поведении, так и во взглядах. Не буду таить, и внешне очень красивая. Хотя это я узнал позже при встрече. Зовут её Алёна. В начале 2009-го года я понял, что Алёна мне не безразлична. Так получилось, что она стала наставлять меня по взаимоотношению с девушками, что я воспринял с полной готовностью. К тому моменту, мне и самому было ясно, что со мной что-то не так: с девушками не клеется. Наша дружба привела к следующему.

В феврале 2009-го года я ехал в троллейбусе и услышал из динамиков рекламу курсов Норбекова. Алёна мне давно советовала сделать лазерную коррекцию зрения, так как знала о её успешных результатах. Но, так как я уже плотно познакомился с Google, первым делом проверил мнение людей в Интернете. Оказалось, что существовал некий способ восстановления зрения по Норбекову. В момент, когда я услышал рекламу, я понял, что это то самое, куда мне нужно абсолютно точно проследовать. Алёна меня поддержала.

После посещения разных ступеней и разных курсов Норбекова я уже увереннее задышал жизнью. Стал больше верить в себя. Зрение, к сожалению, не восстановил, но это уже было не важно. На этих курсах я познакомился со среднего возраста мужчиной, который посещал к тому же ещё и "Русский стиль рукопашного боя". Таким образом я попал на рукопашный бой, который посещал с июня по ноябрь 2009-го.

Летом 2009-го года с группой рукопашного боя и кадетами школы милиции мы ходили в поход в Кузнецкий алатау.
До этого похода Алёна мне много раз советовала жить одному, т.к. такая возможность у меня была (и есть), но я не соглашался. По возвращении с похода я понял, что нужно начать уже жить без мамы.

В августе я стал жить отдельно. Сначала было очень одиноко, но потом привык.
Тем не менее, мне всё равно не давала покоя Алёна, её душевные муки. Очень они меня задевали (и из этой статьи станет понятно почему). Очень были мучительны для меня. Я не мог не помочь.
Поэтому я обратился именно к тому психологу, которого посещала Алёна несколько раз. К сожалению, ничего значительного почерпнуть я у него не смог. Думаю, не мой подход. Но, к счастью, он дал свою аську, поэтому я ещё несколько раз консультировался без личной встречи.

В один из моментов, когда я сильно волновался за Алёну, я опять решил спросить помощи у Евгения (психолога). И даже посмел рассказать про вопросы Алёны. Психолог сначала посетовал, но я всё равно выпрашивал у него решение, и он подсказал мне обратиться к другому психологу - Ольге Фёдоровне, которая, как я это выяснил позже, специализируется на психоанализе.
К Ольге Фёдоровне я и отправился с твёрдым намерением помочь Алёне. Где-то на втором или третьем посещении она поставила вопрос ребром, сказав, что не может помочь Алёне через меня, ей нужна именно сама Алёна. И спросила, почему помощь Алёне меня так волнует.

Я ходил к ней где-то с сентября 2009-го года раз в неделю. И хожу до сих пор, сегодня март 2010-го. И сегодня я подобрался к теме статьи. Благодаря Ольге Фёдоровне я переосмыслил много лет своей жизни, своё отношение ко всем и ко всему. И сегодня, 11-го марта 2010-го года, мы дошли до очень важного, очень больного для меня момента. Даже не только для меня, для России.

В школу я пошёл в 1993-м году в Ростове-на-Дону. Я жил с мамой в однокомнатной квартире, т.к. она развелась с отцом, когда мне было 4 года. Они поделили двухкомнатную квартиру на две однокомнатных.
В школе у меня, как я сегодня вспомнил, были друзья. Мы с ними играли после школы. В том самом и смежных дворах, где была однокомнатная квартира.
Всё было хорошо. Друзья, двор, школа.

Года четыре спустя (6-й класс) родственники помогли со средствами и мама поменяла однокомнатную квартиру на двухкомнатную в другом дворе. Он находился где-то в 20-30 минутах ходьбы от прежнего. Школа осталась та же, но... двор уже был не тот. В этом дворе у меня уже не было друзей. Я пытался познакомиться с ребятами с нового двора, но, к сожалению, переезд наложил на меня отпечаток. В этом дворе я получил непримечательную кличку, обозначавшую, что я нахожусь на последней ступени эволюции. Или точнее на самой начальной, если идти от более простых форм жизни к более сложным. После этого переезда я закрылся в некоторой степени от мира. И перестал общаться с теми друзьями, что были в старом дворе. Возможно, это был страх. Не помню. Я просто не знал, что можно (и нужно) поддерживать связь.

Именно в этот год я попробовал курить, но один. Да и не в затяг. Это и спасло. Изоляция "спасла". Через 1.5 месяца бросил, т.к. "не вкурил".
Хотя у меня в школе появился новый друг, который жил недалеко от меня, в соседнем дворе, минут 5 ходьбы. К нему мы, бывало, ходили играть в денди перед школой, т.к. учились со второй смены. Помню даже название игры - Zen. Помню, что у него даже был компьютер, но, т.к. он был старшего брата, мы к нему не прикасались.

Но шёл уже 1998-й год. Да-да, наш любимый Ельцин. Наш любимый кризис. Теперь я уже лично ненавижу этих демократов, которые, как я теперь понял, сломали жизнь и мне, школьнику, у которого и денег-то не было. Хотя тогда ни у кого денег не было. А в 1998-м году вообще не стало.
Это был очередной переломный момент в моей жизни.
В 7-й класс я уже пошёл в городе Кемерово, в первую школу. Кризис вынудил маму приехать в Кемерово, т.к. здесь вся родня. В Ростов-на-Дону она уехала с моим отцом.
Здесь уже друзей не было. Были какие-то знакомые, но ни с кем из той школы я сейчас не общаюсь. Да и имён не помню. Кроме двух людей, с которыми я встретился позже.
Летом перед 7-м классом, когда я был тут, если не ошибаюсь, на летних каникулах у бабушки, даже писал маме письмо, в котором просил её не уезжать из Ростова, потому что... мне нравилась одна девочка...

В 8-м классе я опять пошёл в старую школу, но уже в другой класс. Мама улаживала последние дела с квартирой, чтобы навсегда свалить с Ростова. Поэтому я опять оказался в Ростове, но Ростов этот уже был совсем иной для меня.
Пошёл я в более продвинутый класс, нежели был в 6-м, в котором остался тот друг из соседнего двора, с которым мы играли в денди. Может быть, и та девочка. Не помню.
Это был очередной удар. Помню, что я тогда перед директором школы даже плакал, что не хочу в другой класс. Мне сказали, что с такими хорошими оценками мне там не место. Оценки... они думали об оценках.

В 9-м классе я жил опять у бабушки в Кемерово. Мама уже приобрела квартиру здесь в Кемерово. Именно в 9-м классе у меня начало ухудшаться зрение. К моему сожалению, я пошёл к глазному и он советовал мне не надевать очки, чтобы не испортить зрение. Я настоял на очках. И испортил зрение. Сейчас очки не ношу специально, чтобы не усугублять далее ситуацию.
Это уже была даже другая школа. Не та, в которую я пошёл в 7-м классе. Видимо, оценки "испортились" в Ростове... где у меня появился друг.

Поэтому пошёл я в 40-ю школу города Кемерово. И туда же пошёл Григорий, с которым я учился в 7-м классе в первой школе города Кемерово. С ним мы и сидели поначалу за одной партой, если не изменяет память. Потом появились ещё знакомые в школе. Даже, думаю, друзья появились, хотя с ними я сейчас не общаюсь, поэтому не могу точно сказать, друзья ли были. В 9-м классе я уже не знал, что такое дружба. Да и сейчас с трудом вспоминаю.

После 40-й школы я пошёл в КемГУ на математический. Окончил в 2008-м.
И вот, после более полугода посещения психолога я подошёл к ужасным моментам своей жизни. Которые буквально сломали меня, которые заставили меня закрыться в себе, возненавидеть мир... и прочее. Сейчас я вспоминаю эти ужасные моменты и плачу, пока набираю этот текст... Это было ужасно, это был ад. Как только я находил друзей, у меня их отбирали, меня кидали в новое место. На ум приходит лишь сравнение с морским пехотинцем. Но ребёнок не воин. Тем более в 6-м классе.

Если бы не всё это, я бы врядли был тем, кем являюсь, но у меня были бы друзья. Те самые старые добрые друзья, которых у меня теперь нет. Есть новые, но отношения, к сожалению, с ними не такие крепкие, какие мне хотелось бы иметь. Во многом, из-за того, что я сам не особо иду на контакт из-за сильных ушибов жизнью.

Поэтому хочу сказать одно: берегите детей. Ни при каких обстоятельствах не переезжайте даже из двора во двор, вы сломаете ребёнку жизнь. В лучшем случае, он закроется и не сопьётся, возможно даже будет искать помощи и наткнётся на психолога. Но это ад. Это ужасно. Этого я никому не желаю. Лучше пусть будет один двор, одна школа, старые добрые друзья, новые друзья от старых друзей, но не несколько городов и несколько школ.

Пожалуйста, не ломайте детям жизнь переездами.

пятница, 19 февраля 2010 г.

Сор в избе

Рабочий день 12-го февраля начался необычно. Как только я пришёл на работу, сослуживец кинул мне ссылку на внутренний форум технической поддержки конторы провайдера, где я работаю. Суть темы в том, что провайдер убрал тариф "Первый+", не уведомив об этом пользователей, что положено по договору.
Весь текст темы
После прочтения этой темы я добавил следующее:

Интересно узнавать о работе других отделов из сообщений на форуме. Жаль, что даже внутри всё держится в секрете.
В связи с этим вспоминается принцип Кирхгофа:

... чем меньше секретов содержит система, тем выше её безопасность. Так, если утрата любого из секретов приводит к разрушению системы, то система с меньшим числом секретов будет надёжней. Чем больше секретов содержит система, тем более она ненадёжна и потенциально уязвима. Чем меньше секретов в системе — тем выше её прочность.

Математическое обоснование честности.

После моего сообщения сослуживец добавил следующее:

Наши IT-шники предложили...

Это особенно мило... Йа "горд" за компанию

Часов в 12 я отправился на обед. По возвращении обнаружил, что наши сообщения удалили, а тему закрыли. Также мне сообщили, что со мной хотел поговорить Kir, он же генеральный директор. В итоге со мной поговорил Сергей, начальник отдела ПО. Потом он также поговорил и с сослуживцем.
Мне вменялся вынос сора из избы. "Разговор" был построен таким образом, что я должен был почувствовать себя предателем. К слову сказать, Сергей привёл интересный (и неверный) пример: "Если тебе будет изменять жена и всем об этому трубить, тебе будет приятно?".
Никому я, естественно, не изменял. Но то, что я публично высказался о внутренних проблемах конторы, меня заинтересовало самого. Я обсудил этот случай с несколькими знакомыми и с психологом.
Выяснилось, что я сделал публичное высказывание из-за того, что не доверяю начальству - Сергею, Kir'у и т.д..
Причины для этого имеются: моё мнение начальство не интересует, мои предложения тоже.
Видимо, поэтому я и захотел "отделиться" от конторы, потому что таким обманом была попрана честь всех сотрудников конторы, что меня, естественно, не устроило. Другие сослуживцы говорили, что им стыдно говорить, что они работают в этой конторе, такая у неё репутация.
Вот такие пироги...