Subscribe: Zápisník Davida Majdy
Added By: Feedage Forager Feedage Grade B rated
Language: Czech
book  change  climate  code  design  it’s  language  lisp  ood  problem  recursion  rust  software  things  time  že   
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: Zápisník Davida Majdy

David Majda

David Majda’s personal website

Copyright: Copyright © 2000–2018 David Majda

Hello, Energomonitor!

Mon, 06 Feb 2017 07:00:00 -0000

Yesterday, I described how I learned about climate change and realized its importance. At first I become depressed about the severity and depth of the problem, but then I started looking for ways how I can help with solving it.

First steps

The first thing I did was trying to lower my personal carbon footprint. This is something everyone can (and should!) do and it involves limiting activities that release a lot of carbon into the atmosphere (in the form of greenhouse gases). I won’t go into the details here as everyone interested can find a lot of resources on the internet. But I found it interesting that low carbon footprint correlates pretty much 100% with leading a non-consumer lifestyle.

The second thing I did was give a talk about what I learned (in Czech). This felt like a logical step — when most people don’t know about the problem, it’s worth educating them.

But I wanted to do more. I’m a software engineer and software is inside everything these days. There must be a way to contribute by doing what I know best — building software. So I started looking around.

It it well known that climate change is linked with the energy sector. One of the best ways to mitigate it is by being smarter about energy production, consumption, and distribution. Unfortunately, this is mostly a domain of big utility companies — the last place where I could imagine myself working at. But there are also startups that try to attack the problem from the sidelines, mostly with unconventional approaches.

One of these startups is Energomonitor, a maker of smart devices that measure energy consumption and help to optimize it. I followed the company for some time and liked what it was doing. When Energomonitor started looking for people to strengthen its software development team, I didn’t hesitate and applied. And the result is that I’m starting to work as software development lead at Energomonitor today.

The job will be full of challenges. New role, new problem area, new set of technologies, new set of people, etc. But I’m confident I’ll be able to handle these and help the company succeed while contributing — in a tiny but not unimportant way — to mitigating the climate change.

Wish me luck :-)

Bye bye, sabbatical!

Sun, 05 Feb 2017 08:00:00 -0000

In the past months I’ve been on a sabbatical, with an intention to spend some time on open source, learning, and reflection. This sabbatical ends today. For many reasons it ended up being a different and more transformative journey then I expected and in this post I’d like to describe some important things I learned. Tomorrow, you’ll see where this led me. Climate change One of the topics I always wanted to explore but didn’t have the time was the climate change 1. I heard about it in the news since my childhood, but all I knew was that it has something to do with greenhouse gasses and rising ocean levels. I wanted to learn more. What exactly causes it? What is the current state? Are people in danger? What will happen if the we don’t do anything about it? And can we do something? What exactly? What is the cost of these measures? Wouldn’t it make more sense to just adapt? And there were many more questions like that. So, one day I entered “climate change” into Google and started digging. What I learned After a week or so of intensive study, I learned enough to realize that climate change is much bigger and more dangerous problem than most people realize. To the best of our knowledge, the whole thing is caused entirely by us, humans — specifically by releasing CO2 and other greenhouse gasses to atmosphere, mainly as a result of burning fossil fuels. This has already raised the average global temperature over 1 °C higher above pre-industrial times, and the trend continues — 2016 was the hottest year on record, surpassing 2015, which in turn surpassed 2014. The temperature is rising. Source: Gavin Schmidt If we do nothing about this, the temperature increase will reach 4 °C or more at the end of the century. This will have a multitude consequences, including widespread droughts, ocean level rise (because of thawing icebergs) and extreme climate (because the climate system will contain more energy). These will have devastating effects in many areas and will cause mass migration (from areas that become too dry to live in or flooded). All this will almost certainly cause conflicts and massive loss of life and property. The world 4 °C warmer. Source: Parag Khanna What’s worse, climate is a non-linear, unstable system with many built-in positive feedbacks. This means that once the warming crosses a critical threshold, we will be powerless to stop it. We would just watch the temperatures slowly go up while more and more areas of our planet would become unhabitable. No one is sure where exactly this point of no return lies, which makes it even more urgent to deal with the problem sooner than later. What now? When I learned the above (and much more), it left me quite depressed. It was clear that climate change is a huge problem that can easily lead to the end of the life as we know it. So I went to see what can be done about it. It turns out that the biggest part of the problem is burning fossil fuels to produce energy. To mitigate climate change, we have to be smarter about energy production, consumption, and distribution. Specifically, we need to convert the electricity production to non-carbon sources (wind, solar, nuclear) and be more serious about energy savings. Obviously, this is a huge political and technical challenge. The carbon challenge. Source: Roger Pielke Jr. Once you have a clean electric grid, you can attack another part of the problem: transportation. Currently it’s all based on oil, but at least for cars there is an obvious path forward: electrify them. Again, a huge challenge, but it’s not like it’s not being worked on. Learning this, I began to think about whether I can maybe help somehow. And that will be the topic of my next post tomorrow. Want to learn more about the climate change? A good start is an award-winning 2016 documentary Before the Flood or older An Inconvenient Truth. You can also start at Wikipedia. For more comprehensive treatment, I recommend Climate [...]

Rust impressions

Fri, 03 Feb 2017 09:10:00 -0000

Few days ago I decided to have a look at Rust. I wanted to do this for some time, mostly because Rust seemed like an interesting emerging language that might play an important role in the future. Here are my high-level observations. Complexity The dominating feeling when learning Rust and playing with is was being overwhelmed with complexity. There are lot of concepts in the language and lot of things one needs to know to understand and write Rust programs. Part of that complexity is because of the type system. Rust’s type system is powerful and expressive, which naturally leads to a multitude of built-in types and to quite complex type definitions and specifications. This problem is not unique to Rust — in the past, I had a similar feeling from Scala and Julia, which also have quite powerful type systems. I actually don’t think that type system complexity is that big of a problem. In practice, it will tend to be confined to libraries — mostly the ones that define various data structures. An application programmer probably won’t need to understand all of the type system’s features and nuances in order to write programs successfully. This is similar to situation in C++, where I doubt that most programmers are able to fully comprehend the implementation of STL. Another part of the complexity comes from the borrow checker (the part that makes Rust secure and prevents things like dangling pointers). This is a truly new concept and as such completely unfamiliar. To me, it sometimes felt like a type system squared — first, I had to make my code to satisfy the type system and then the borrow checker. Of course, in reality you have to do both at once and I imagine with complex programs it might sometimes feel like a whack-a-mole. The bad thing about complexity coming from the borrow checker is that it won’t hide in the libraries. Application programmers will have to deal with it all the time. The good thing is that the rules are not that hard and I think can get used to them quickly. In most cases, they really only formalize thinking that any C/C++ programmer must do anyway. More observations Compared to other languages, I found Rust programs harder to follow (in the sense of knowing exactly what is happening in each step and simulating the execution in my head). The only other language with which I had this difficulty was C++. But I suspect this feeling would fade with continued usage and growing familiarity. One thing that surprised me a lot is that I’m actually not sure whether I like Rust or not. On one hand it seems well designed, consistent, and fit for its purpose (a fast and secure systems language). On the other hand I prefer simpler languages with smaller set of concepts and features. But this is mostly a matter of taste. Moreover, a lot of complexity seems to be inherent to the problem of designing a secure language with C/C++ level of performance and it would be present in any such language. Use or not? This brings us to the most important questions: Should you use Rust? And when? I think it makes sense to consider Rust when writing complex, performance-critical software which absolutely needs to be secure. Think OpenSSL, Apache, or JVM. This is where previously the only reasonable choice was C/C++. If your software doesn’t have critical performance requirements, it’s probably wiser to use more high-level language — be it something from the managed languages family (Java, C#) or the scripting languages family (PHP, Python, Ruby, JavaScript). There, most of the safety that Rust guarantees is achieved by automating memory management. If your software isn’t complex or the security isn’t critical (e.g. when writing a backend service that will not face the internet), but you still need performance, Go or even C/C++ might be a better choice. This will allow you to avoid the complexity cost. Conclusion Rust brings innovation into an important area of systems programming which was occupied mostly by C++ until now. Despite my re[...]

Using my education (finally)

Thu, 30 Apr 2015 07:30:00 -0000

One thing I really like on my current job at Jut as a language designer and implementer1 is that I finally fully use my computer science and mathematical education — even parts I considered too theoretical when I was at university. This is in stark contrast with pretty much all the work I did before where I haven’t needed my education almost at all. Now I can’t do my job properly without it.

In the last few months I used or at least touched:

Behind each of these items is a story where I would have done a bad job without knowing the concept — I would have introduced a badly designed feature, fixed a bug in a wrong way, or simply failed to notice something odd. As a result, Jut’s Juttle language would have looked perceivably worse than it looks now.

So, for all of you who wonder whether computer science and mathematical education is valuable in the age when most software development is mindless gluing of pre-built components together I have an answer: Yes! But you have to look for a job where you will use it.

I talked more about this topic (and told stories behind the items above) at the Prague Ruby meetup (slides).

  1. Really a co-designer and co-implementer — there is a whole team behind Jut’s Juttle language. 

Object-oriented design reading list

Thu, 22 Jan 2015 07:30:00 -0000

When I was teaching a university course about writing clean and maintainable code about 8 years ago, there was one topic I touched only lightly: object-oriented design (OOD). The reason was simple — I was struggling with it myself. I was still exploring the topic and had more questions than answers in my head. Unsurprisingly, I wasn’t comfortable teaching it at that stage. Over the years, I gradually learned OOD and became proficient in it. And then I started to see that some of my colleagues at SUSE (my employer at the time) are in the same situation I was few years ago. They understood objects and classes at the technical level, but had trouble partitioning problems into classes and methods, and struggled with designing larger object systems. I decided to help them. Shortly before I left the company I prepared and sent around a reading list consisting of materials (videos, websites, and books) about OOD and related topics. The idea was to give everyone a starting point to begin learning OOD on his/her own. Today, I share this list with you — in pretty much the original form. The list is split by topics and carefully arranged so that it makes sense to go through it top to bottom. If you actually read everything and reach the end, you won’t suddenly become the world’s brightest OOD designer, but I can promise you’ll feel the difference. And you’ll never look at your old code the same way :-) Enjoy! Object-oriented design Sandi Metz: Go Ahead, Make a Mess (video) Software is always a mess, but not every mess is equal. This talk shows how to manage bad kinds of messes and how to convert them into good ones. It introduces various OOD principles and demonstrates how an OO designer thinks about dependencies and knowledge. Sandi Metz: Rules (video) In this talk Sandi introduces 4 rules that naturally lead towards creating small objects with small methods and separating business logic from framework code. These rules are proxies to creating software more efficiently. As a bonus, the talk includes general discussion about rules and their following. Sandi Metz: All the Little Things (video) Here an ugly piece of conditional code is gradually refactored into few simple objects. Along the way, you’ll learn few things about duplication, abstractions, open/closed principle, inheritance hierarchies, and applying a “squint test” to assess code quality. Sandi Metz: Practical Object-Oriented Design in Ruby (book) If you liked Sandi’s talks, you’ll like her book even more. It introduces many OOD principles in accessible way, explains motivation behind them, and discusses trade-offs involved. It’s the best OOD book for beginners I know of. Robert C. Martin: Clean Code: A Handbook of Agile Software Craftsmanship (book) This book is about writing clean code in general, but since OOD has overlap with that topic, it will also teach you some bits of it. The most useful part for many will probably be an extended example, where a piece of bad code gets gradually rewritten into much better shape. Michael Feathers: Working Effectively with Legacy Code (book) Michael’s definition of legacy code is “any code that doesn’t have tests”. The book describes how to tame such code and add tests over time, which will allow you to make changes with confidence. The book is filled with examples of both untestable and testable code and shows various techniques how to covert the former to the latter. And because testable and well-designed code are highly correlated, the book also teaches good software design along the way. SOLID Wikipedia: SOLID (object-oriented design) (web) Entry point to get an overview about SOLID. Sandi Metz: SOLID Ob[...]

Two questions to ask after a bugfix

Thu, 08 Jan 2015 07:30:00 -0000

As a programmer, you probably spend large part of your time by fixing bugs. The workflow is always the same: Debug a problem, find its cause, prepare a fix, merge it into the codebase, mark the underlying issue as resolved — and you are done. Right?

Well, not quite. There is one important step missing. At the very end, you should always ask the following two questions:

  1. Can this bug occur elsewhere?
  2. How could it have been prevented?

Let’s have a look at them in detail.

Can this bug occur elsewhere?

Code often contains repeated patterns that can’t be easily abstracted away. If you fix a bug in one instance of such pattern, it’s worth trying to find the other instances and fix the bug there too. For example, when you add a missing NULL constraint for one attribute in one database table, it makes sense to check the whole schema for similar omissions.

When fixing all the instances you’ll often discover deeper problems. For example, in case of NULL constraints you can find out that you allow/disallow NULLs rather randomly — there is no consistent policy. The fix is not just making the schema consistent, but also establishing this policy and documenting it.

Which leads us to the second question…

How could it have been prevented?

Every bug was introduced because somebody made an error. It’s worth investigating why that error happened. Was it a simple omission? Was it a copy and paste error? Was it an unintended consequence of some other change? Was it because of wrong assumptions of the implementor? Was it because of poor understanding of the code?

Often there are multiple causes of an error. They form a chain, where each step is derived from the previous one by asking “why”. If possible, establish at least first few links of this chain. 1

Once you have done that, try to think of ways how the bug could have been prevented at each level. Then implement as many of these fixes as you can. The best solutions cover the deepest links of the chain, which means they solve relatively generic issues and prevent whole classes of bugs.

Here is an example (in a form of an imaginary conversation):

A: We had a cross-site scripting bug at our website.
B: Why?
A: Because the front-end programmer forgot to call the HTML escaping function.
B: Why?
A: Because he is a human and humans forget things occasionally.
B: Why?
A: Because of how their brans are wired. It can’t really be changed.
B: OK, let’s stop here. Because we can’t change how human brain works, we need to adapt our tools to fit it better. Let’s change the templating code to escape everything by default so the escaping can’t be forgotten.

You see? We ended up with a generic fix preventing a whole class of problems.


Asking questions discussed above after each bugfix will naturally guide you from one-off fixes to discovery of deeper problems with your code, processes, or maybe your team. If you are diligent in fixing them, your bug rate will go down over time and you’ll end up writing better software. And that’s what you want, isn’t it?

  1. In reality, the chain is often a tree, because there are multiple valid answers to some of the “whys”. But let’s stick with the chain metaphor for simplicity. 

On Ruby’s Lisp heritage

Sun, 14 Dec 2014 13:50:00 -0000

If you are a Ruby programmer, you probably know that some methods in Ruby’s Enumarable module are available under multiple different names. For example:

  • map is the same as collect
  • find_all is the same as select
  • reduce is the same as inject
  • find is the same as detect

Why is that?

The answer is simple. Names like map and reduce were traditional in Lisp circles. And all the names ending with “-ect” described the same concepts in various Smalltalk environments. Since Ruby philosophy is to try to please everyone (as opposed to forcing one officially blessed way), it incorporated names from both worlds.

Usage in the wild

It’s interesting to see which names are more often used in the real world. In most codebases I’ve seen, Lisp won. Pretty much everyone uses map, find, and find_all rather than collect, detect, and select. The only exception is inject, which seems to be used more often than reduce.

I’m not sure why this is the case. Is it because the Lisp names are shorter? Is it because the Smalltalk names are all alike? I don’t know, but I suspect the main factor is familiarity. More programmers knew the Lisp names rather than the Smalltalk ones when they started writing Ruby code, so they used them, and this convention spread.

Is Ruby Lisp?

Widespread use of Lisp names for common operations supports a notion that Ruby has a Lisp heritage. This notion is repeated by many, but I actually think it is superficial. If you look closely at the language, you’ll find no trace of Lisp at all. The core or Ruby is actually a dynamic flavor of Smalltalk with Perl features added on top.

So is Ruby’s Lisp heritage a myth? I’d call it so, if it weren’t for one thing — Matz once said he started with Lisp when he designed the language. With this in mind, I can only say that the Lisp core was all but wiped out by his later design steps.

Thanks to Martin Vidner for inspiring me to write this post.

The story of recursion

Sun, 07 Dec 2014 18:10:00 -0000

Recently I’ve read a fascinating, well researched article on how recursion got into mainstream programming — or, more specifically, into ALGOL 60, from which many contemporary languages descend from. It made me realize three things: Activation record allocation was once static. Recursion is hard to avoid. You can circumvent design by committee. Let’s have a detailed look at each of these. Activation record allocation was once static Every function1 needs some space to store its local variables and passed parameters when it’s called. This space is called its activation record. Today, activation records are usually organized into a stack that grows and shrinks as needed. But in the 50’s, it was apparently common to allocate activation records statically. There was just one pre-allocated record for each function. This obviously meant that each function could be active only once, prohibiting recursion. Allowing recursion meant switching from static activation record allocation to a dynamic, stack-based one. It was controversial at the time (presumably because it had performance and complexity implications), and it was the main reason why some people resisted adding recursion into ALGOL 60 at the time. Somehow, I always thought that the stack and functions came together. Apparently, they did not. Recursion is hard to avoid It’s really hard to prevent recursion when you have functions. First, you need to prohibit direct recursion by not allowing functions to call themselves in their bodies. Next, you need to analyze the call graph at compile-time to detect instances of indirect recursion (alternatively, you can just disallow forward function declarations). But the real trouble starts when you introduce pointers to functions. Once you have them, recursion can sneak in by passing a pointer as a parameter somewhere. It can’t be checked statically anymore. If you don’t want to have recursion in your language, you have to do work, and even then, it’s a futile battle. To me, this suggests that recursion is a natural concept (for some definition of natural). If a language has functions, recursion should be allowed. You can circumvent design by committee The ALGOL 60 language was specified in a document called the ALGOL 60 Report. It was produced by a committee, yet it was an example of a compact and elegant text. This is not usually the case. How was that possible? It turns out that the committee was circumvented by one determined individual — Peter Naur. He consolidated ALGOL design discussion that was happening at the time, produced a draft of the ALGOL 60 Report just before the final design conference, and handed it out to its attendees. Because the confernece’s limited time span, they didn’t have much choice but to accept this draft as the basis of discussion. As Friedrich L. Bauer (member of the design group) recalls: Peter Naur had not been commissioned to do so, it was a fait accompli. It therefore sounds poetic if he has written that his draft Report was ‘chosen’ as the basis of the discussion; the Committee was simply forced to do so, after Peter Naur had gained this advantage. After the conference, Peter Naur became the editor of the report, and kept it under control. This example shows it is possible to get good results even in the presence of a committee. All it takes is a capable individual taking over the work and maneuvering the committee into a position where the easiest and most reasonable course of action is to go with what this individual proposes. I have to admit I’ve used variations on this strategy few times at SUSE. It usually worked, and sometimes the “committee” didn’t even realize it was circumvented. Conclusion To get the full picture of the recursion story, I can only recommend you to read the article yourself. And big thanks to Ladislav Thon for making me no[...]

Jak matfyz učí přemýšlet

Sun, 23 Oct 2011 12:30:00 -0000

O matfyzu a zejména o matematických předmětech, které se na něm vyučují, se říká, že „učí přemýšlet“. Dlouho to pro mě byla prázdná fráze, ale myslím, že už vím, co znamená. Ukážu to na jednoduchém příkladu.

Dnes ráno u snídaně jsem se zamyslel nad tím, proč různým lidem chutnají různé věci. Tuhle otázku jsem měl ve skutečnosti v hlavě už několik měsíců, ale nejspíš se vždy vynořila v nevhodný okamžik, takže jsem ji doteď neprozkoumal.

Rozumně vypadá teorie, že to pro lidi kdysi dávno muselo být evolučně výhodné. Zkusil jsem si tedy představit situaci, kdy by všichni lidé měli chutě úplně stejné, a porovnat ji se skutečným stavem. Zřejmě by jedli méně různých věcí, a tím pádem se ochuzovali o živiny z těch, které by jim nechutnaly (ty by nejspíš jedli jen v nouzi). Navíc by se o ono omezené množství hádali – co by jeden přinesl, to by všichni okamžitě chtěli (nikdo by nad tím neohrnul nos). Nejspíš by taky snáz došlo k tomu, že by lidé vyčerpali zdroje chutných plodin na daném území, což by vedlo k větší migraci se všemi nevýhodami s tím spojenými.

Zdá se, že alternativní verze reality opravdu vypadá méně výhodná a různorodost chuti dává jistý evoluční smysl. S tímto závěrem jsem průzkum myšlenky opustil (vědom si samozřejmě toho, že má úvaha byla jen lehké naťuknutí a je spousta faktorů, které jsem nejspíš pominul a situaci by zkomplikovaly).

Objevila se ale jiná otázka: jak mě napadlo, že mám při ověřování teorie „různorodost chuti je evolučně výhodná“ otočit hypotézu a kouknout se na věc z druhé strany – tedy prozkoumat situaci, kdy by chuť všech byla stejná, a zjistit, k čemu povede? Tenhle nápad se v mé hlavě objevil naprosto spontánně, prakticky ihned po formulaci zmíněné teorie. To znamená, že jsem ho už někde musel vidět.

Pak mi to došlo – důkaz sporem. Větu „pro spor předpokládejme, že tvrzení neplatí“ jsem během svého studia na matfyzu slyšel mockrát, a sám jsem tuto techniku důkazu mnohokrát aplikoval. Je to myšlenkový vzor, který mám v hlavě uložený velmi hluboko, a můj mozek intuitivně pozná situaci, kdy ho použít. Byť třeba velmi neformálně jako dnes.

Takových myšlenkových vzorů mám v hlavě pravděpodobně několik desítek. Používám je nejspíš denně, aniž bych si to uvědomoval. Urychlují analýzu situací, pomáhají mi porovnávat a rozhodovat, umožňují okamžitě vidět logické klamy a nesmysly. A právě na matfyzu (nebo na jiné obdobné škole) se člověk tyto vzory při studiu matematiky naučí a bude je používat každodenně několik let. Dostanou se mu pod kůži a jejich použití se zautomatizuje. A přesně tohle je význam oné věty „matfyz učí přemýšlet“.

Neříkám, že k těmto vzorům není možné přijít i jinak, než studiem matematiky na matfyzu. Ale je to ověřená a systematická cesta. A je to také to podstatné, co si ze studia matematiky lze odnést. Integrály a diferenciální rovnice totiž zapomenete, ale naučené způsoby myšlení s vámi zůstanou celý život.

Tlaky při vydávání software

Sun, 05 Sep 2010 14:00:00 -0000

Představte si softwarovou firmu, která vyvíjí klasický krabicový software. Tento software má vývojový cyklus o délce několika měsíců. Na jeho konci se nachází několik betaverzí, release candidates a nakonec finální verze – vše s přesně danými termíny. Nyní se nacházíte někde mezi betaverzemi a dle výsledků testování a počtů nacházených chyb začíná být jasné, že bude problém software dokončit v původně plánovaném termínu a se všemi funkcemi. Co můžete v tuto chvíli jako manažer produktu dělat? Klasické poučky softwarového inženýrství říkají, že musíte buď posunout termín vydání, nebo vyškrtnout funkce, které ještě nejsou hotové nebo jsou příliš chybové a nestihly by se odladit. Případně můžete obojí zkombinovat. (Je tu ještě třetí možnost: snížit kvalitu výsledku a neopravovat chyby, ale tu nyní zanedbejme – předpokládejme, že chcete vydat kvalitní produkt.) Problém je, že ať už budete chtít vydat produkt později, nebo ho ořezat, typicky narazíte na velké síly, které vám v tom budou bránit. Několik příkladů: Posun termínu Datum vydání produktu už bylo veřejně oznámeno (změna zhorší vnímání vaší firmy jako schopné dodávat produkty dle plánu). Datum je svázáno s vydáním jiných vašich produktů (svým posunem posunete i je, změnu může být těžké dojednat a sníží reputaci vás i vašeho týmu). Už bylo vykonáno mnoho práce počítající s plánovaným datem (např. zadání reklamní kampaně na produkt do médií na dané období). Datum je navázáno na nějako pevnou událost, kterou nelze posunout (např. konference). Vyškrtání funkcí Funkce prodávají (čím méně funkcí, tím méně prodaných kopií produktu). Seznam nových funkcí už byl veřejně oznámen (změna zhorší vnímání vaší firmy jako schopné dodávat produkty dle plánu). S novými funkcemi počítají vaši stávající zákazníci (nedodáte-li je, můžou přejít ke konkurenci). Na vašich funkcích závisejí jiné produkty firmy (svým omezením donutíte k omezení i je, změnu může být těžké dojednat a sníží reputaci vás i vašeho týmu). Už bylo vykonáno mnoho práce počítající s plánovanými funkcemi (např. příprava reklamní kampaně na produkt do médií, která je zdůrazňuje). Sil je samozřejmě víc, záleží také na konkrétních okolnostech. Prakticky všechny se ale přímo či nepřímo redukují na finanční ztráty pro firmu. Z toho plyne, že bude vždy existovat velice silný tlak na to, aby byly původní termín a seznam funkcí dodrženy. Tento tlak bude vždy nejvíce pociťovat manažer produktu, protože to je především on, kdo rozhoduje, kterým směrem se jeho vývoj vydá. Je proto možné, že místo uvedených možností zvolí jiné řešení – zvýší tlak na programátory a další členy týmu, aby produkt dodělali včas a úplný. Nařídí se přesčasy, začne horečné opravování chyb na posledních chvíli, hackování místo čistých řešení problémů atd. Tato cesta je velmi nebezpečná, protože na rozdíl od prvních dvou nemá přímé negativní finanční konsekvence (krom případných proplacených přesčasů) – ty se projeví až mnohem později. Manažerovi tedy nic nebrání po ní jít, je to pro něj defaultní volba. Jak daleko po cestě se vydá záleží v podstatě jen na kultuře firmy a na tom, jak hodně jsou její zaměstnanci ochotní nechat věci vyhrotit. Co se stane, pokud zajdeme příliš daleko? Tým bude vyčerpaný a demoralizovaný, což může vést k odchodům lidí nebo ztrátě jejich motivace a tedy horším pracovním výkonům a poklesu iniciativy. K[...]