Übersetzung vorschlagen
 
Andere Vorschläge:

progress indicator
Keine anderen Vorschläge
MSDN Magazin > Home > Ausgaben > 2009 > MSDN Magazin August 2009 >  Inkrementelle Übertragung durch fortlaufende De...
Inhalt anzeigen:  Englisch mit deutscher ÜbersetzungInhalt anzeigen: Englisch mit deutscher Übersetzung
Dies sind maschinell übersetzte Inhalte, die von den Mitgliedern der Community bearbeitet werden können. Sie können die Übersetzung verbessern, indem Sie auf den jeweils zum Satz gehörenden Link "Bearbeiten" klicken.Mithilfe des Dropdown-Steuerelements "Inhalt anzeigen" links oben auf der Seite können Sie zudem bestimmen, ob nur der englische Originaltext, nur die deutsche Übersetzung oder beides nebeneinander angezeigt werden.
Patterns in Practice
Incremental Delivery Through Continuous Design
Jeremy Miller
In earlier Patterns in Practice columns, I've focused mainly on technical "patterns," but in this article I'll discuss the softer "practice" side of software design. The end goal of software projects is to deliver value to the customer, and my experience is that software design is a major factor in how successfully a team can deliver that value. Over design, under design, or just flat out wrong design impedes a project. Good design enables a team to be more successful in its efforts.
My experience is also that the best designs are a product of continuous design (also known as emergent or evolutionary design) rather than the result of an effort that tries to get the entire design right up front. In continuous design, you might start with a modicum of up-front design, but you delay committing to technical directions as long as you can. This approach lets you strive to apply lessons learned from the project to continuously improve the design, instead of becoming locked into an erroneous design developed too early in the project.
In addition, I firmly believe that the best way to create business value is through incremental delivery of working features rather than focusing first on building infrastructure. In this article, I'll explore how incremental delivery of working features enables a project team to better deliver business value, and how using continuous design can enable incremental delivery to be more efficient and help you create better software designs.

Predictive versus Reactive Design
First of all, what is software design? For many people, software design means "creating a design specification before coding starts" or the "Planning/Elaboration Phase." I'd like to step away from formal processes and intermediate documentation and define software design more generally as "the act of determining how the code should be structured." That being said, we can now think of software design happening in two different modes: predictive or reactive (or reflective if you prefer).
Predictive design is the design work you do before coding. Predictive design is creating UML or CRC models, performing design sessions with the development team at the beginning of iteration, and writing design specifications. Reactive design is the adjustments you make based on feedback during or after coding. Refactoring is reactive design. Every team and even individuals within a team have different preferences in using predictive or reactive design. Continuous design simply puts more importance on reactive design than does traditional software development processes.
Incremental Delivery of Features
In 2002, my then-employer was experimenting with the newly minted Microsoft .Net Framework and had launched a trial project using ASP.NET 1.0. I, along with many others, eagerly watched the project, hoping for success so that we could start using this exciting new framework on projects of our own. Six months later the project was canceled. The team had certainly been busy, and by all accounts it had written a lot of code, but none of that code was suitable for production.
The experience of that project team yields some important lessons. The team first wrote a design specification that was apparently fairly complete and conformed to our organization's standards. With this document in hand, the team started the project by attempting to build the entire data access layer, then the business logic layer, and finally the user interface. When they started to code the user interface screens, the developers quickly realized that the existing data access code wasn't exactly what they needed to build the user interface, even though that code conformed to the design documents. At that point, IT management and the business partners didn't see any value being delivered by the project and threw in the towel in favor of other initiatives.
Ironically, to me the parent company was and is one of the world's leading examples of a lean or just-in-time manufacturer. Most of our competitors used "push" manufacturing, in which large quantities of parts are ordered for factory lines based on the forecasted demand over some period of time. The downfalls of push manufacturing are that you lose money any time you order more parts than you can use; you have to pay extra to store the stocks of surplus parts before you're ready to use them; and you are vulnerable to part shortages on the factory floor any time the forecasts are wrong—and forecasts are rarely accurate.
In contrast, my then-employer used "pull" manufacturing. Several times a day the factory systems scheduled the customer orders they needed to build over the next couple of hours, determined the quantities of parts they needed to complete those orders, and then ordered for immediate delivery exactly the number and type of parts needed. The advantages of pull manufacturing are that by buying only what is needed, you waste much less money on parts that can't be used; factories have far fewer on-hand part stocks to contend with, making manufacturing somewhat more efficient; you can quickly adapt to new circumstances and market forces when you aren't bound by forecasts made months ago; and forecasts and estimates are more accurate when made over the short term rather than a longer term.
So how does the pull versus push issue apply to software development? The failed project I described earlier used push design by trying to first determine all the infrastructural needs of the system and then trying to build out the data access infrastructure before writing other types of code. The team wasted a lot of effort designing, documenting, and building code that was never used in production.
Instead, what if the team had settled for quickly writing a high-level specification with minimal details, then proceeded to develop the highest-priority feature to production-ready quality, then the next highest-priority feature, and so on. In this scenario, the team would build out only infrastructure code, like data access code, that was pulled in by the requirements of the particular feature.
Think about this. What is a better outcome for a project at the end of its scheduled timeline?
  1. 1.Only 50 percent of the proposed features are complete, but the most important features of the initial project proposal are ready to deploy to production.
  2. 2.Most of the coding infrastructure is complete, but no features are completely usable and nothing can be deployed to production.
In both cases the team is only roughly half done and neither outcome is truly a success compared to the initial plan and schedule. But which "failure" would you rather explain to your boss? I know my boss and our sales team would definitely prefer the first outcome based on incremental delivery.
The key advantages of incremental delivery are the following:
  1. Working in order of business priority. Building incrementally by feature gives you a better chance to complete the features most important to the business. After all, why should you spend any time whatsoever designing, building, and testing a "nice to have" feature before the "must have" features are complete?
  2. Risk mitigation. Frankly, the biggest risk in most projects isn't technical. The biggest risk is that you don't deliver business value or you deliver the wrong system. Also, the harsh reality is that the requirements and project analysis given to you is just as likely to be wrong as your design or code. By demonstrating working features to the business partners early in the project, you can get valuable feedback on your project's requirements. For my team, early demonstrations to our product manager and sales team have been invaluable for fine-tuning our application's usability.
  3. Early delivery. Completed features can be put into production before the rest of the system to start earning some return on value.
  4. Flexible delivery. Believe it or not, the business partners and your product manager sometimes change their priorities. Instead of gnashing your teeth at the injustice of it all, you can work in such a way that assumes that priorities will change. By tying infrastructure code to the features in play, you reduce the likelihood of wasted effort due to changing priorities.
Now, for the downside of incremental delivery: it's hard to do. In the lean manufacturing example, pull manufacturing worked only because the company's supply chain was ultraefficient and was able to stock factories with parts almost on demand. The same holds true for incremental delivery. You must be able to quickly design the elements of the new features and keep the quality of the code structure high enough that you don't make building future features more difficult. What you don't have time to do is spend weeks or even months at a time working strictly on architectural concerns—but those architectural concerns still exist. You need to change the way you design software systems to fit the incremental delivery model. This is where continuous design comes into the picture.

Continuous Design
Proponents of traditional development often believe that projects are most successful when the design can be completely specified up front to reduce wasted effort in coding and rework. The rise of Agile and Lean programming has challenged traditional notions of the timing of software design by introducing a process of continuous design that happens throughout the project life cycle. Continuous design purposely delays commitments to particular designs, spreads more design work over the life cycle of the project, and encourages a team to evolve a design as the project unfolds by applying lessons learned from the code.
Think of it this way. I simply won't develop the detailed design for a feature until it's time to build that feature. I could try to design it now, but that design work wouldn't provide any benefits until much later—and by the time my team gets to that feature, I'm likely to understand much more about our architecture and system and be able to come up with a better design than I could have at the beginning of the project.
Before I go any further, I'd like to say that continuous design does not imply that no design work takes place up front. I like this quote from Robert C. (Uncle Bob) Martin : " The goal is to create a small but capable initial design, and then maintain and evolve that design over the life of the system ."
Before you write off continuous design as risky and prone to error, let's discuss how to make continuous design succeed (in other words, I'm going to try to convince you that this isn't crazy).

The Importance of Feedback
Many projects are truly straightforward, with well- understood requirements, and strictly use well-known technologies. Up-front design might work fairly well with these projects, but my experience is the opposite. Almost every project I've worked on has had some degree of novelty, either in the technology used, the development techniques employed, or in the requirements. In those cases, I believe that the best way to be successful is to adopt an attitude of humility and doubt. You should never assume that what you're doing and thinking works until you have some sort of feedback that verifies the code or design.
Because continuous design involves the evolution of the code structure, it's even more important when using that approach to create rapid feedback cycles to detect early errors caused by changes to the code. Let's take the Extreme Programming (XP) model of development as an example. XP calls for a highly iterative approach to development that remains controversial. Almost as controversial is the fact that XP specifies a series of practices that are somewhat difficult to accept for many developers and shops. Specifically, XP practices are largely meant to compensate for the rapid rate of iteration by providing rapid and comprehensive feedback cycles.
  • Collective ownership through pair programming. Love it or hate it, pair programming requires that at least two pairs of eyes review each and every line of production code. Pair programming provides feedback from a design or code review mere seconds after the code is written
  • Test-driven development (TDD), behavior-driven development (BDD), and acceptance tests. All these activities create very rapid feedback. TDD and BDD help drive out defects in the code when initially written, but just as important, the high level of unit-test coverage makes later design changes and additions to the code much safer by detecting regression failures in a fine-grained way.
  • Continuous integration. When combined with a high level of automated test coverage and possibly static code analysis tools, continuous integration can quickly find problems in the code base each and every time code is checked in.
  • Retrospectives. This requires that the development team stop and discuss how the software design is helping or hurting the development effort. I've seen numerous design improvements come out of iteration and release retrospectives.
The quality and quantity of your feedback mechanisms greatly affect how you do design. For example, high automated test coverage with well-written unit tests makes refactoring much easier and more effective. Refactoring with low or no automated test coverage is probably too risky. Poorly written unit tests can be almost as unhelpful as having no tests whatsoever.
The reversibility of your code is greatly enhanced by solid feedback mechanisms.
The Last Responsible Moment
If not up front, when do you make design decisions? One of the most important lessons you learn through continuous design is to be cognizant of the decisions you make about your design and to consciously decide when to make those decisions. Lean programming teaches us to make decisions at the "last responsible moment." According to Mary Poppendieck (in her book Lean Software Development), following this principle means to "delay commitment until … the moment at which failing to make a decision eliminates an important alternative."
The point is to make decisions as late as possible because that's when you have the most information with which to make the decision. Think back to the failed project I described at the beginning of this article. That team developed and committed to a detailed design for the data access code far too early. If the developers had let the user interface and business logic needs drive the shape of the data access code as they built the user interface features, they could have prevented quite a bit of wasted effort. (This is an example of "client-driven design," where you build out the consumer of an API first in order to define the shape and signature of the API itself.)
One of the key ideas here is that you should think ahead and continuously propose design changes, but you shouldn't commit irrevocably to a design direction until you have to. We don't want to act based on speculative design. Committing early to a design precludes the possibility of using a simpler or better alternative that might present itself later in the project. To quote a former colleague, Mike Two of NUnit 2 fame, "Think ahead yes, do ahead no."

Reversibility
Martin Fowler says, "If you can easily change your decisions, this means it's less important to get them right—which makes your life much simpler." Closely related to the last responsible moment is the concept of reversibility, which I would describe as the ability or inability to change a decision. Being cognizant of the inherent reversibility of your decisions is essential to following the principle of the last responsible moment. The first decision my team made for a recent project was whether to develop with Ruby on Rails or stay with a .NET architecture. Choosing a platform and programming language is not an easily reversible decision, and we knew we needed to make that decision early. On other projects, I've had to coordinate with external groups that needed to define and schedule their time months in advance. In cases like those, my team absolutely had to make decisions up front to engage with the external teams.
A classic decision involving reversibility is whether to build caching in an application. Think about cases where you don't know for sure if you really need to cache some piece of data. If you're afraid that caching will be impossible to retrofit later, you invariably have to build that caching at the start—even though that may be a waste of time. On the other hand, what if you've structured the code to isolate the access to this data in such a way that you could easily retrofit caching into the existing code with little risk? In the second case, you can responsibly forgo the caching support for the moment and deliver the functionality faster.
Reversibility also guides my team in what technologies and techniques we use. Because we use an incremental delivery process (Kanban with Extreme Programming engineering practices), we definitely favor technologies and practices that promote higher reversibility. Our system will probably have to support multiple database engines at some point in the future. To that end, we use an Object Relational Mapping framework to largely decouple our middle tier from the actual database engine. Just as important, we've got a fairly comprehensive set of automated tests that exercise our database access. When it's time to swap database engines, we can use those tests to be confident that our system works with the new database engine—or at least point out exactly where we're incompatible.

YAGNI and the Simplest Thing that Could Possibly Work
To do continuous design, we have to make our code easy to change, but we'd really like to prevent a lot of rework in our code as we're making changes to it. To do incremental delivery, we want to focus on building only the features we're tasked with building right now, but we don't want to make the next feature impossible or harder to develop by making the design incompatible with future needs.
Extreme programming introduced two sayings to the development vernacular that are relevant here: "You aren't gonna need it" (YAGNI, pronounced "yawg-nee"), and "The simplest thing that could possibly work."
First, YAGNI forbids you to add any code to the system now that will not be used by current features. " Analysis paralysis" in software development is a very real problem, and YAGNI cuts through this problem by forcing you to focus on only the immediate problem. Dealing with complexity is hard, but YAGNI helps by reducing the scope of the system design you need to consider at any one time.
Of course, YAGNI can sound scary and maybe even irresponsible because you might very well need the level of complexity you bypassed the first time around. Following YAGNI shouldn't mean that you eliminate future possibilities. One of the best ways to ensure that is to employ "the simplest thing that could possibly work."
I like Alan Shalloway's definition of the simplest thing that could possibly work shown in the following list. (The once-and-only-once rule refers to the elimination of duplication from the code; it's another way of describing the "don't repeat yourself" principle). You should choose the simplest solution that still conforms to these rules:
  1. Runs all the tests.
  2. Follows the once-and-only-once rule.
  3. Has high cohesion.
  4. Has loose coupling.
These structural qualities of code make code easier to modify later.
The point of these complementary sayings is that each piece of complexity has to earn its right to exist. Think about all the things that can happen when you choose a more complex solution over a simpler one:
  1. The extra complexity is clearly warranted.
  2. The extra complexity isn't necessary and represents wasted effort over a simpler approach.
  3. The extra complexity makes further development harder.
  4. The extra complexity turns out to be flat-out wrong and has to be changed or replaced.
The results of adding complexity include one positive outcome and three negative outcomes. In contrast, until proven otherwise, a simple solution may be adequate. More important, the simple approach will probably be much easier to build and to use with other parts of the code, and if it does have to be changed, well, it's easier to change simple code than complex code. The worst case scenario is that you have to throw away the simple code and start over, but by that time you're likely to have a much better understanding of the problem anyway.
Sometimes a more complex solution will definitely turn out to be justified and the correct choice, but more often than not, using a simpler approach is better in the end. Consistently following YAGNI and "the simplest thing" when you're in doubt is simply following the odds.

How Much Modeling Before Coding?
Let's put documentation requirements aside for the moment. Here's a classic question in software development: "How much design and modeling should I do before starting to code?" There is no definitive answer because every situation is different. The key point here is that when you're unsure how to proceed, this means you are in a learning mode. Whether you do some modeling or exploratory coding first strictly depends on which approach helps you learn faster about the problem at hand, and, of course, I have to repeat this classic quote from Bertrand Meyer: "Bubbles don't crash."
  • If you're working with an unfamiliar technology or design pattern, I think that modeling isn't nearly as useful as getting your hands dirty with some exploratory coding.
  • If a design idea is much easier for you to visualize in a model than in code, by all means draw some models.
  • If you have no idea where to start in the code, don't just stare at the IDE window hoping for inspiration. Take out a pen and paper and write down the logical tasks and responsibilities for the task you're working on.
  • Switch to coding the second that you reach a point of diminishing returns with modeling. (Remember, bubbles don't crash!) Better aligning the boxes in your diagram does not help you write better code!
  • If you do jump straight into coding and begin to struggle, stop and go back to modeling.
  • Remember that you can switch between coding and modeling. Many times when you're confronted with a difficult coding problem, the best thing to do is pick out the simplest tasks, code those in isolation, and use the form of that code to help you determine what the rest of the code should look like.
Another thing to keep in mind is that some forms of modeling are more lightweight than others. If UML isn't helping you with a problem, switch to CRC cards or even entity relationship diagrams.

What's Ahead
This article had no code whatsoever, but I feel strongly that these concepts apply to almost all design decisions. In a future column, I'll talk about some specific concepts and strategies for developing designs that allow you to use continuous design principles. I'll also describe in much more detail how refactoring fits into continuous design.

Send your questions and comments to mmpatt@microsoft.com .

Jeremy Miller , a Microsoft MVP for C#, is also the author of the open-source StructureMap tool for Dependency Injection with .NET and the forthcoming StoryTeller tool for automated acceptance testing in .NET. Visit his blog, " The Shade Tree Developer ," part of the CodeBetter site.

Muster in der Praxis
Inkrementelle Übertragung durch fortlaufende Design
Jeremy Miller
In früheren Muster in Übung Spalten ich haben konzentriert sich hauptsächlich auf technische "Muster", aber in diesem Artikel erörtert die weichere "praktischen"-Seite der Softwareentwurf. Das Endziel von Softwareprojekten ist Wert an den Kunden zu liefern und meiner Erfahrung ist Software Design ein wesentliche Faktor wie erfolgreich ein Team den Wert übermitteln kann. Über Entwurf behindert unter Design oder nur flach out falschen Entwurf ein Projekts. Ein guter Entwurf ermöglicht ein Team mehr in seine Bemühungen erfolgreich durchgeführt werden.
Meiner Erfahrung ist auch, dass die besten Entwürfe eines Produkts kontinuierliche Design (auch bekannt als Beseitigung oder evolutionären Design), sondern das Ergebnis der Bemühungen, die versucht sind, das gesamte Motiv vorab richtig hinzubekommen. In fortlaufende Entwurf beginnen Sie möglicherweise mit einer Modicum Weise entwerfen, aber Sie verzögern Commit Technische Anweisungen wie möglich. Dieser Ansatz ermöglicht Ihnen die bemüht zuweisen gewonnenen Erkenntnisse aus dem Projekt den Entwurf, statt immer in einen fehlerhaften Entwurf zu früh in das Projekt entwickelt gesperrt kontinuierlich zu verbessern.
Darüber hinaus glauben ich fest, dass die beste Möglichkeit Business Wert zu erstellen durch inkrementelle Bereitstellung von Features arbeiten, sondern konzentriert sich zuerst auf Aufbau Infrastruktur ist. In diesem Artikel werde ich wie inkrementelle Bereitstellung von Features ermöglicht arbeiten untersuchen ein Projektteams besser übermitteln Geschäftswert, und wie mit fortlaufenden Design aktivieren kann inkrementelle Bereitstellung effizienter und Ihnen helfen, bessere Software Entwürfe erstellen.

Im Vergleich zu reaktive Design Vorhersage
Was ist zunächst einmal Softwareentwurf? Für viele Personen, die Software "startet Entwurf bedeutet Erstellen einer Entwurfsspezifikation vor der Codierung" oder "Planung-Ausarbeitung Phase der." Ich würde gern zu Schritt away from formale Prozesse intermediate-Dokumentation und definieren Sie Softwareentwurf im Allgemeinen mehr als "der Vorgang des bestimmen, wie der Code strukturiert werden soll." Die gerade gesagt, wir können sich jetzt vorstellen Softwareentwurf in zwei verschiedenen Modi: Vorhersagemodellierung oder reaktiv (oder Reflektierend, falls gewünscht).
Vorhersagbare Entwurf ist der Entwurfsarbeit vor dem codieren möchten. Vorhersagemodellierung Entwurf erstellen UML oder CRC-Modelle, Entwurf Sitzungen mit dem Entwicklungsteam die zu Beginn der Iteration ausführen und Designspezifikationen schreiben. Reaktiver Entwurf ist die Anpassungen, die basierend auf Feedback während oder nach dem Codieren, die Sie vornehmen. Umgestaltung ist reaktiver Entwurf. Jedes Team und sogar Personen innerhalb eines Teams haben verschiedene Einstellungen in Vorhersage oder reaktiver Entwurf verwenden. Kontinuierliche Design fügt einfach weitere Wichtigkeit auf reaktiver Entwurf als herkömmliche Softwareentwicklungsprozessen.
Inkrementelle Bereitstellung von Features
Mein dann-Arbeitgeber in 2002 wurde das Experimentieren mit neu minted Microsoft .NET Framework und mussten mit ASP.NET 1.0 ein Testversion Projekt gestartet. I, beachtet zusammen mit vielen anderen unverzüglich das Projekt, für den Erfolg Hoffnung, so dass wir mithilfe dieses interessante neue Framework auf unseren eigenen Projekte starten konnte. Sechs Monate später wurde das Projekt abgebrochen. Das Team war sicherlich ausgelastet ist, und von allen Konten war es viel Code geschrieben, aber keines dieser Code wurde für die Produktionsumgebung geeignet.
Die Erfahrung, dass das Projektteam führt einige wichtigen Lektionen. Das Team schrieb zuerst eine Entwurfsspezifikation, die scheinbar ziemlich abgeschlossen und conformed Standards für unsere Organisation war. Mit diesem Dokument in der Hand gestartet das Team das Projekt, indem Sie Versuch, die gesamte Datenzugriffsschicht dann die Geschäftslogikschicht und schließlich die Benutzeroberfläche zu erstellen. Beim Starten, die Benutzer Schnittstelle Bildschirme zu codieren, realisierter die Entwickler schnell nicht vorhandenen Datenzugriffscode was Bedarf, die Benutzeroberfläche zu erstellen, obwohl Code in den Dokumenten entwerfen entsprach genau war. An, Punkt, IT-Verwaltung und der Geschäftspartner haben finden Sie einen Wert vom Projekt übermittelt werden und in Handtuch zugunsten von anderen Initiativen ausgelöst hat.
Ironischerweise, mir der Muttergesellschaft war und ist eines der weltweit führenden Beispiele ein Hersteller neigen oder Just-in-Time. "Die meisten unserer Mitbewerber verwendet verschieben" Produktion, in dem große Mengen von Teilen für Factory Positionen basierend auf den prognostizierten Bedarf über einige Zeitraum bestellt werden. Downfalls der Push-Produktion sind, verlieren Sie Money jederzeit bestellen Sie weitere Teile als Sie verwenden können; Sie bezahlen zusätzliche um Aktien überschüssige Teile zu speichern, bevor Sie diese; verwenden möchten und Sie Teil Engpässe in der Fabrik anfällig sind, jederzeit die Planungen falsch sind – und Prognosen sind selten genau.
Im Gegensatz dazu wird mein dann-Arbeitgeber "Pull" Produktion verwendet. Mehrmals am Tag, den der Factory-Systeme die Kundenbestellungen geplanten Bedarf über das nächste paar Stunden, erstellen, bestimmt die Mengen der Teile, die Sie zum Abschließen dieser Aufträge erforderlich, die und dann für sofortige Übermittlung genau die Anzahl und Art der benötigten Teile bestellt. Die Vorteile des Pull-Produktion sind, vom Kauf nur was benötigt wird, Sie verschwenden Sie viel weniger Geld auf Teile kann nicht verwendet werden; Factorys haben zu konkurrieren mit viel weniger Lagerbestand Bestandteil Aktien Produktion etwas effizienter machen; Sie können schnell an neue Situationen anpassen und Vermarkten erzwingt, wenn Sie sind nicht durch Prognosen vor; Monaten gestellt und Prognosen gebunden und Schätzungen genauer, wenn über die kurzfristig statt mehr Begriff vorgenommen.
Wie gilt Pull und Push Problem für Softwareentwicklung? Fehlgeschlagene Projekt ich früher verwendeten Push Entwurf von versuchen, zunächst alle infrastructural Anforderungen des Systems ermitteln und außerhalb der Datenzugriffsinfrastruktur zu erstellen, bevor Sie andere Arten von Code schreiben möchten beschrieben. Das Team verschwendet viel Aufwand entwerfen, Dokumentieren und Erstellen von Code, der nie in der Produktion verwendet wurde.
Stattdessen, was geschieht, wenn das Team hatte schnell Schreiben einer allgemeinen Spezifikation mit minimalen Details ausgeglichen, und dann fortgesetzt, die höchste Priorität zu entwickeln, Produktion einsetzbaren Qualität, dann das nächste höchste Priorität Feature, das feature und usw.. In diesem Szenario würde das Team, nur Infrastrukturcode, wie Datenzugriffs-Code erstellen, die von den Anforderungen von bestimmten Features, in abgerufen wurde.
Überlegen Sie diese. Was ist ein besseres Ergebnis für ein Projekt am Ende der geplanten Zeitachse?
  1. 1. Nur 50 Prozent der vorgeschlagenen Features vollständig sind, aber die wichtigsten Features des Angebots Anfangsprojekt sind in der Produktionsumgebung bereitstellen.
  2. 2. Die meisten der Codierung Infrastruktur abgeschlossen ist, jedoch keine Funktionen vollständig verwendbar sind, und nichts in die Produktion bereitgestellt werden kann.
In beiden Fällen das Team ist nur ungefähr Hälfte durchgeführt und weder Ergebnis ist tatsächlich ein Erfolg im Vergleich zu den ursprünglichen Plan und den Zeitplan. Aber welche "Fehler" würde stattdessen erklären Sie an Ihren Chef? Ich weiß mein Chef und unsere Vertriebsteam würde definitiv das erste Ergebnis basierend auf Inkrementelle Bereitstellung bevorzugen.
Die Hauptvorteile von inkrementellen Übermittlung sind die folgenden:
  1. Arbeiten in der Reihenfolge des Unternehmens Priorität. Erstellen inkrementell vom Feature haben Sie die bessere Möglichkeit um die Features für das Unternehmen wichtigsten abzuschließen. Schließlich sollten Sie warum jederzeit investieren, überhaupt entwerfen, erstellen und eine "nice," Funktion testen, bevor die Features "müssen haben" abgeschlossen werden?
  2. Risiko zur Risikominimierung. Offen gesagt, ist das größte Risiko in den meisten Projekten technischen nicht. Das größte Risiko ist, dass Sie nicht Geschäftswert übermitteln, oder Sie das falsche System übermitteln. Darüber hinaus die anspruchsvoll Realität ist, dass die Anforderungen und Projekt Analyse, die Sie ist nur als wahrscheinlich falsche als Entwurf oder Code. Durch demonstrieren Features arbeiten mit Geschäftspartnern frühzeitig im Projekt, können Sie wertvolles Feedback zu den Anforderungen Ihres Projekts abrufen. Mein Team wurden frühe Demos an unser Produkt-Manager und Sales Team unschätzbarem Wert für die Feineinstellung unserer Anwendung Benutzerfreundlichkeit.
  3. Frühzeitige Bereitstellung. Abgeschlossene Funktionen können in der Produktionsumgebung vor dem Rest des Systems starten bei einigen Rendite Wert einfügen.
  4. Flexible Bereitstellung. Ob Sie es glauben oder nicht ändern Sie die Geschäftspartner und Ihr Produktmanager manchmal deren Prioritäten. Anstatt Ihre Zähne zu Unrecht es alle Knirschen, können Sie in einer Weise arbeiten, die wird davon ausgegangen, dass Prioritäten geändert werden. Blockieren Infrastrukturcode zu den Features in spielen, verringern Sie die Wahrscheinlichkeit von ungenutzten Aufwand aufgrund von Prioritäten zu ändern.
Jetzt, für der Nachteil der inkrementellen Lieferung: schwierig werden. Im Beispiel schlanke Produktion pull Produktion bearbeitet nur da Lieferkette des Unternehmens ultraefficient war und vordefinierte Factorys mit Teilen fast bei Bedarf konnten. Dasselbe gilt für die inkrementelle Übermittlung. Sie müssen in der Lage, schnell Designelemente der neuen Features und halten Sie die Qualität der Codestruktur hoch genug, dass Sie vornehmen künftige Features schwieriger zu erstellen. Was Sie dazu keine Zeit haben ist Wochen oder sogar Monate gleichzeitig arbeiten ausschließlich architektonische Fragen aufwenden, jedoch noch die architektonischen Aspekte. Sie müssen die Möglichkeit, Entwerfen Sie Softwaresysteme inkrementelle Delivery-Modell entsprechend ändern. Dies kommt kontinuierliche Design in das Bild.

Kontinuierliche Design
Befürworter der herkömmlichen Entwicklung häufig glauben, dass Projekte erfolgreichsten, sind wenn der Entwurf vorab vollständig angegeben werden kann überflüssige Aufwand im Code reduzieren und überarbeiten. Die Rise of Agile und kurzen Programmierung hat herkömmlichen Konzepte für die zeitliche Steuerung der Softwareentwurf Aufforderung, durch die Einführung eines Prozess kontinuierliche Design, das während der Projektdauer geschieht. Kontinuierliche Design absichtlich verzögert Verpflichtungen zu bestimmten Entwürfen, verbreitet sich mehr Entwurfsarbeit über den Lebenszyklus des Projekts und fördert ein Team ein Entwurfs weiterentwickeln, wie das Projekt durch Anwenden von Erfahrungsberichten aus dem Code kann.
Betrachten Sie diese Möglichkeit. Ich wird nicht einfach den detaillierten Entwurf für ein Feature entwickeln, bis das Feature zu erstellen. Ich könnte versuchen, es jetzt entwerfen, aber, Entwurfsarbeit würde nicht bieten Vorteile erst viel später – und nach meinem Team auf die Funktion ruft, ich bin wahrscheinlich viel mehr über unsere Architektur und System verstehen und in der Lage erarbeiten sich mit einem besseren Entwurf als habe am Anfang des Projekts konnte.
Bevor ich weiter, möchte ich sagen, dass kontinuierliche Design nicht impliziert, dass keine Entwurfsarbeit vorab erfolgt. Ich möchte Dieses Angebot von Robert C. (Onkel Bob) Martin : " Das Ziel ist ein kleiner, aber kann anfängliche entwerfen, erstellen und verwalten und weiterentwickelt, Entwurf für die Lebensdauer des Systems ."
Bevor Sie aus fortlaufenden Entwurf als riskant und fehleranfällig schreiben, erläutern wir, wie fortlaufende erfolgreich entwerfen (anders gesagt, ich werde versuchen, Sie davon überzeugen, dass diese verrückte nicht).

Die Bedeutung von Feedback
Viele Projekte sind wirklich einfach, mit gut-verstanden Anforderungen und ausschließlich bekannte Technologien verwenden. Vorfeld Design möglicherweise ziemlich gut mit diesen Projekten arbeiten, aber meiner Erfahrung ist das Gegenteil. Nahezu jedes Projekt auf bearbeiteten wurde ein gewisses Maß an modische, in die Technologie verwendet, die Entwicklungstechniken beschäftigt, oder die Anforderungen. In diesen Fällen glauben ich, dass die beste Möglichkeit erfolgreich sein ist ein Haltung von Humility und zweifelhaft übernehmen. Sie sollten nie voraus, dass was Sie sind ausführen und denken funktioniert, bis Sie eine Art von Feedback haben, die den Code oder Entwurf überprüft.
Da fortlaufende Entwurf die Weiterentwicklung der Codestruktur umfasst, ist es sogar noch wichtiger, wenn frühen durch Änderungen am Code verursacht Fehler erkennen diesen Ansatz verwenden Zyklen, um schnelle Feedback zu erstellen. Werfen Sie das Modell Extreme Programming (XP) für die Entwicklung als Beispiel. XP ruft für einen hochgradig iterativen Ansatz zur Entwicklung, die umstrittene bleibt. Fast wie umstrittene ist die Tatsache, XP gibt eine Reihe von Methoden an, die schwierig für viele Entwickler und Geschäfte akzeptieren sind. Insbesondere XP Vorgehensweisen größtenteils sollen die schnelle Rate der Iteration kompensieren, indem Sie eine schnelle und umfassende Feedbackzyklen.
  • Gemeinsame Besitz über Paar Programmierung. Liebe es oder hasse es, Paar Programmierung erfordert, dass mindestens zwei Paare von Augen jede Produktion Codezeile überprüfen. Paar Programmierung bietet Feedback von einen Entwurf oder Code überprüfen nur Sekunden nach dem der Code geschrieben ist
  • Testgesteuerten Entwicklung (TDD) Verhalten datengesteuerten Entwicklung (BDD) und Akzeptanz Tests. Alle diese Aktivitäten erstellen sehr schnell Feedback. TDD und BDD Hilfe Laufwerk aus Fehlern im Code Wenn anfänglich geschrieben, aber ebenso wichtig, hohe Einheit Testabdeckung macht später Entwurfsänderungen und Ergänzungen der Code wesentlich sicherer durch Regression Fehler präzise Weise erkennen.
  • Kontinuierliche Integration. Zusammen mit einer hohen automatisierte Testabdeckung und möglicherweise statischen Codeanalysetools finden kontinuierliche Integration schnell Probleme in der Codebasis jedes Mal Code eingecheckt wurde.
  • Auswertung. Dies erfordert, dass das Entwicklungsteam beenden, und erläutern, wie die Softwareentwurf helfen oder den Entwicklungsaufwand beeinträchtigt wird. Ich habe zahlreiche Entwurfsverbesserungen stammen aus der Iteration und Freigeben von Auswertung gesehen.
Die Qualität und Menge der Feedback-Mechanismen wirken sich auf erheblich wie entwerfen Sie. Hoch automatisierte Testabdeckung mit gut geschriebenem Einheit testet z. B. Umgestaltung viel einfacher und effektiver macht. Refactoring mit wenig oder keine automatisierten Testabdeckung ist wahrscheinlich zu riskant. Schlecht geschriebene Komponententests kann fast wie als müssen keine keinerlei testet.
Die Reversibility des Codes wird durch einfarbige Feedback Mechanismen erheblich verbessert.
Der Last verantwortlich Zeitpunkt
Wenn nicht voraus, wenn Sie nehmen Entwurfsentscheidungen? Eine der wichtigsten Lektionen, die Sie, über fortlaufende Entwurf erfahren ist der Entscheidungen cognizant werden Sie über den Entwurf, und entscheiden, wann diese Entscheidungen consciously soll. Schlanke Programmierung vermittelt uns Entscheidungen Zeitpunkt"Letzte verantwortlich." Nach Mary Poppendieck (in Ihr Buch kurzen Softwareentwicklung) folgenden dieses Prinzip bedeutet, "Engagement bis … Verzögerung der Zeitpunkt, an welche fehlschlagen stellen eine Entscheidung wichtige Alternative beseitigt."
Der Punkt ist, Entscheidungen so spät wie möglich zu treffen, da, wenn Ihnen die meisten Informationen mit denen die Entscheidung. Denken Sie an das fehlgeschlagene Projekt am Anfang dieses Artikels beschriebenen. Das Team entwickelt und viel zu früh an einen detaillierten Entwurf für Datenzugriffs-Code übergeben. Wenn die Entwickler die Benutzeroberfläche lassen mussten und Geschäftslogik Laufwerk muss die Form des Datenzugriffs-Code, während der Erstellung des Benutzers Features der Benutzeroberfläche, haben Sie konnte etwas vergeblicher Bemühungen verhindert. (Dies ist ein Beispiel für "Client-gesteuerte Entwurf", erstellen Sie außerhalb der Consumer einer API zunächst um Form und Signatur der API selbst zu definieren.)
Einer der wichtigen Ideen ist, sollten Sie nun denken und kontinuierlich vorschlagen Entwurfsänderungen, aber Sie sollten nicht unwiderruflich zu eine Richtung Entwurf zusichern bis zu. Wir möchten fungieren basierend auf spekulative Entwurf. Commit frühzeitig zu einem Design verhindert die Möglichkeit, eine einfachere oder eine bessere Alternative, die sich selbst weiter unten in das Projekt möglicherweise verwenden. Um einen ehemaligen Kollegen, Mike 2 von 2 NUnit Ruhm Angebot "Think nun Ja, ahead keine führen."

Reversibility
Martin Fowler angezeigt wird, "Wenn Sie Ihre Entscheidungen problemlos ändern können, dies bedeutet weniger wichtig, um rechts zu erhalten, wodurch Ihr Leben viel einfacher." In engem Zusammenhang mit dem letzten ist verantwortlich Moment das Konzept der Reversibility, denen ich als Möglichkeit oder Unfähigkeit, eine Entscheidung ändern würde. Wird von der inhärenten Reversibility Ihre Entscheidungen cognizant unbedingt zu das Prinzip der im letzten Moment verantwortlich. Die erste Entscheidung mein Team für die aktuelle Projekt wurde, ob mit Ruby on Schienen entwickeln oder bleiben Sie mit einer Architektur .NET vorgenommen. Auswählen einer Plattform und Programmiersprache ist keine Entscheidung leicht umkehrbar, und wir wussten wir mussten, frühzeitig Entscheidung. Auf andere Projekte habe ich musste mit externen Gruppen zu koordinieren, die zum Definieren und Planen Ihre Zeit Monate im Voraus erforderlich. In den Fällen mussten mein Team absolut vorab zu Einbindung mit externen Teams Entscheidungen treffen.
Eine klassische Entscheidung im Zusammenhang mit Reversibility ist, ob Zwischenspeicherung in eine Anwendung zu erstellen. Fälle, in denen Sie vergewissern Sie sich kennen möchten Sie wirklich einige Datenbestandteil Zwischenspeichern, überlegen. Wenn Sie fürchten sind, dass Zwischenspeichern unmöglich, später Nachrüstung werden, haben Sie ausnahmslos erstellen, Zwischenspeichern am Anfang – Obwohl, Zeitverschwendung möglicherweise. Andererseits, haben was passiert, wenn Sie strukturierte den Code, der Zugriff auf diese Daten in einer solchen Weise zu isolieren, dass Sie problemlos Nachrüstung konnte Zwischenspeicherung in den vorhandenen Code mit geringem Risiko? Im zweiten Fall aus können Sie hinsichtlich die Zwischenspeicherung Unterstützung für den Moment einfach aufzugeben und die Funktionen schneller zu übermitteln.
Reversibility führt auch mein Team in welche Technologien und Verfahren wir verwenden. Da wir eine inkrementelle Übermittlungsprozess (Kanban mit engineering Vorgehensweisen Extreme Programming) verwenden, bevorzugen wir definitiv Technologien und Methoden, die höhere Reversibility zu fördern. Unser System müssen wahrscheinlich mehrere Datenbankmodule irgendwann in der Zukunft unterstützen. Zu diesem Zweck verwenden wir ein Framework Object Relational Mapping, um unsere Zwischenebene von tatsächlichen Datenbank-Engine größtenteils entkoppeln. Ebenso wichtig haben wir einen ziemlich umfassenden Satz von automatisierten Tests, bei denen unsere Datenbank zugreifen. Wenn es Zeit für Datenbankmodule vertauschen ist, können wir diese Tests verwenden, um sicher sein, dass unser System mit der neuen Datenbank-Engine funktioniert – oder zumindest hinweisen genau, wo wir nicht kompatibel sind.

YAGNI und die einfachste Thing, die möglicherweise funktionieren kann
Kontinuierliche Design hierzu wir zu unseren Code so ändern Sie erleichtern haben, aber wir möchten wirklich viel Überarbeitung in unserem Code zu verhindern, wie wir Änderungen daran vornehmen. Inkrementelle Bereitstellung hierzu wir konzentrieren, erstellen nur die Features, die wir beauftragt sind mit jetzt erstellen möchten, aber wir möchten nicht das nächste Feature unmöglich oder schwerer zu entwickeln, indem Sie den Entwurf nicht kompatibel mit künftigen Anforderungen stellen.
Extreme Programming eingeführt zwei Redensarten zu Entwicklung Vernacular, die hier relevant sind: "Sie sind nicht gonna benötigt" (YAGNI, "Yawg-nee" ausgesprochen), und "Die einfachste Sache, die möglicherweise funktionieren konnte."
Erstens verbietet YAGNI Sie das System beliebigen Code hinzufügen, nun, die von aktuellen Funktionen nicht verwendet werden. " Analyse Lähmungen"in der Softwareentwicklung ist ein sehr reale Problem und YAGNI schneidet über dieses Problem durch erzwingen Sie nur das unmittelbare Problem konzentrieren. Umgang mit Komplexität ist schwierig, aber YAGNI unterstützt, indem reduziert den Umfang der Systementwurf zu einem beliebigen Zeitpunkt berücksichtigt werden müssen.
Natürlich YAGNI kann sound angsteinflößende Angelegenheit und vielleicht sogar irresponsible, da Sie sehr gut Maß an Komplexität möglicherweise Sie umgangen um zum erste Mal. Folgende YAGNI sollte nicht bedeuten, dass Sie zukünftige Möglichkeiten beseitigen. Eine der besten Möglichkeiten, um sicherzustellen, dass besteht darin, "die einfachste Sache." einsetzen, die möglicherweise funktionieren kann
Ich möchte die einfachste Sache, die möglicherweise konnte in der folgenden Liste aufgeführten Alan Shalloway Definition. (Einmal-und-nur-Once-Regel bezieht sich auf die Beseitigung von Duplizierung aus dem Code; eine andere Möglichkeit zur Beschreibung des Prinzips "nicht selbst Wiederholen"). Wählen Sie die einfachste Lösung, die diese Regeln weiterhin entspricht:
  1. Alle Tests ausgeführt.
  2. Einmal-und-nur-Once-Regel folgt.
  3. Hohe Kohäsion hat.
  4. Hat lockeren Kopplung.
Diese strukturelle Merkmale des Codes leichter Code um später ändern.
Der Punkt diese ergänzenden Redensarten ist, dass jeder Teil Komplexität gewinnen rechts davon vorhanden sein. Alle Dinge, die eintreten können, wenn Sie eine komplexere Lösung über eine einfachere überlegen:
  1. Die zusätzliche Komplexität ist klar gerechtfertigt.
  2. Die zusätzliche Komplexität ist nicht notwendig und vergeblicher Bemühungen über ein einfacher Ansatz dar.
  3. Die zusätzliche Komplexität erschwert weiteren Entwicklung.
  4. Die zusätzliche Komplexität erweist sich flat-out falsch und muss geändert oder ersetzt werden.
Die Ergebnisse der Komplexität hinzufügen gehören einem positiven Ergebnis und drei negative Ergebnisse. Im Gegensatz dazu kann bis das Gegenteil erwiesen, eine einfache Lösung ausreichend sein. Noch wichtiger, einfache Ansatz wahrscheinlich viel leichter erstellen und mit anderen Teile des Codes verwendet werden und wenn verfügt auch geändert werden, können Sie leichter einfachen Code als komplizierten Code zu ändern. Der schlimmsten Fall ist, dass Sie wegwerfen einfachen Code, und starten über aber nach der Sie wahrscheinlich ein viel besseres Verständnis des Problems trotzdem sind.
Eine komplexere Lösung wird manchmal definitiv auf im Blocksatz ausgerichtet werden aktivieren und die richtige Wahl, aber mehr häufig als nicht einfacher Ansatz ist besser, am Ende. Konsistent folgenden YAGNI und "das einfachste, was" ist in zweifelhaft einfach die Wahrscheinlichkeit folgt.

Wie viele Modeling vor Programmieren?
Sagen Sie Dokumentationsanforderungen für den Moment einfach reserviert. Hier ist eine klassische Frage bei der Softwareentwicklung: "wie viel entwerfen und Erstellen von Bedrohungsmodellen tun? vor dem Code" Es gibt keine definitive Antwort, da jeder Situation unterscheidet. Der wichtige Punkt hierbei ist, wenn Sie nicht sicher sind, um den Vorgang fortzusetzen, dies bedeutet in einem Modus Learning sind. Ob einige modellieren möchten oder unsystematische Codierung zuerst streng hängt welche Ansatz hilft Sie schneller über das Problem zu erfahren und, besteht natürlich dieses klassische Angebot von Bertrand Meyer Wiederholen: "Blasen nicht abstürzen."
  • Wenn Sie mit einem unbekannten Technologie oder Entwurfsmuster arbeiten, denke ich, dass die Modellierung fast so übersichtlich wie Ihre Hände dirty mit einigen unsystematische Codierung abrufen nicht.
  • Ist eine Vorstellung von Entwurf viel einfacher, die in einem Modell als im Code zu visualisieren, zeichnen Sie durch alle Fall einige Modelle.
  • Wenn Sie keine Ahnung, wo im Code gestartet haben, nicht nur das IDE-Fenster für Inspiration Hoffnung stare. Aus Papier und Stift nutzen Sie und notieren Sie die logische Aufgaben und Zuständigkeiten für die Aufgabe, der Sie arbeiten.
  • Wechseln Sie zur Codierung der Sekunde, die Sie einen Punkt abnehmender Rückgaben mit Bedrohungsmodellen gelangen. (Denken Sie daran, Sprechblasen abstürzen nicht!) Die Felder in Ihrem Diagramm besser ausrichten hilft besseren Code zu schreiben nicht!
  • Wenn Sie direkt in Code springen und beginnen, kämpfen, beenden und zurück zu modellieren.
  • Denken Sie daran, dass Sie zwischen Codieren und Modellierung wechseln können. Oft ist Wenn Sie mit einem schwer Codierung Problem konfrontiert sind, sollten Sie am besten, wählen Sie die einfachsten Aufgaben, code in Isolation und mithilfe des Formulars des Codes können Sie bestimmen, wie der Rest des Codes aussehen sollte.
Eine andere Sache zu beachten ist, dass einige Formulare modellieren einfacher als andere sind. Wenn UML Sie bei einem Problem helfen nicht ist, wechseln Sie zu CRC-Karten oder sogar Entität Beziehung Diagramme.

Was ist machen
In diesem Artikel wurde kein Code überhaupt, aber mein Kollege dringend, dass diese Konzepte auf fast alle Entwurfsentscheidungen angewendet. In einer zukünftigen Kolumne werde ich sprechen über einige bestimmte Konzepte und Strategien für die Entwicklung Entwürfe, die Sie fortlaufende Entwurfsprinzipien verwenden können. Ich werde auch viel genauer beschreiben wie die Umgestaltung in fortlaufenden Entwurf einfügt.

Senden Sie Fragen und Kommentare mmpatt@Microsoft.com .

Jeremy Miller , Microsoft MVP für c#, ist auch der Autor von der Open-Source StructureMap tool für Abhängigkeitsinjektion mit .NET und dem erscheint in Kürze StoryTeller Tool für die automatische Annahme Tests in .NET. Besuchen Sie seinen Blog" SHADE Tree Developer "Teil der CodeBetter-Website.

Page view tracker