`

Clean Code: chapter 11~12

阅读更多

The startup process is a concern that any application must address. It is the first concern
that we will examine in this chapter. The separation of concerns is one of the oldest
and most important design techniques in our craft .

 

Unfortunately, most applications don’t separate this concern. The code for the startup
process is ad hoc and it is mixed in with the runtime logic . Here is a typical example:

 

public Service getService() {
    if (service == null)
        service = new MyServiceImpl(...); // Good enough default for most cases?
    return service;
}
 

We don’t incur the overhead of construction unless we actually use the object, and our startup
times can be faster as a result
. We also ensure that null is never returned.

 

However, we now have a hard-coded dependency on MyServiceImpl and everything its
constructor requires (which I have elided). We can’t compile without resolving these
dependencies, even if we never actually use an object of this type at runtime!

 

One occurrence of LAZY-INITIALIZATION isn’t a serious problem, of course. However,
there are normally many instances of little setup idioms like this in applications
. Hence,
the global setup strategy (if there is one) is scattered across the application, with little
modularity and often significant duplication.

 

Perhaps worst of all, we do not know whether MyServiceImpl is the right object in all
cases. I implied as much in the comment . Why does the class with this method have to
know the global context? Can we ever really know the right object to use here? Is it even
possible for one type to be right for all possible contexts?

 

If we are diligent about building well-formed and robust systems, we should never let
little, convenient idioms lead to modularity breakdown . The startup process of object construction
and wiring is no exception . We should modularize this process separately from
the normal runtime logic
and we should make sure that we have a global, consistent strategy
for resolving our major dependencies .

 

our major dependecies may be this implementation class, may be that implementation class, it should not be wired in the program.

 



Again notice that all the dependencies point from main toward the OrderProcessing
application. This means that the application is decoupled from the details of how to
build a LineItem. That capability is held in the LineItemFactoryImplementation, which
is on the main side of the line. And yet the application is in complete control of when
the LineItem instances get built and can even provide application-specific constructor
arguments.

 

In the context of dependency management, an object should not take responsibility for instantiating dependencies itself .

 

JNDI lookups are a “partial ” implementation of DI, where an object asks a directory
server to provide a “service” matching a particular name.

 

MyService myService = (MyService)(jndiContext.lookup(“NameOfMyService”));

 

The invoking object doesn’t control what kind of object is actually returned (as long it
implements the appropriate interface, of course), but the invoking object still actively
resolves the dependency .

 

True Dependency Injection goes one step further . The class takes no direct steps to
resolve its dependencies
; it is completely passive. Instead, it provides setter methods or
constructor arguments (or both) that are used to inject the dependencies. During the construction
process, the DI container instantiates the required objects (usually on demand)
and uses the constructor arguments or setter methods provided to wire together the dependencies .
Which dependent objects are actually used is specified through a configuration
file or programmatically in a special-purpose construction module.

 

The Spring Framework provides the best known DI container for Java. You define
which objects to wire together in an XML configuration file, then you ask for particular
objects by name in Java code.

 

But what about the virtues of LAZY-INITIALIZATION? This idiom is still sometimes
useful with DI
.

 

The ephemeral nature of software systems makes this possible, as we will see. Let us first
consider a counterexample of an architecture that doesn’t separate concerns adequately .

 

The original EJB1 and EJB2 architectures did not separate concerns appropriately and
thereby imposed unnecessary barriers to organic growth . Consider an Entity Bean for a
persistent Bank class. An entity bean is an in-memory representation of relational data , in
other words, a table row.

 

EJB3 largely follows the Spring model of declaratively supporting cross-cutting concerns using
XML configuration files and/or Java 5 annotations.

 

If the persistence mapping details won’t change frequently , many teams may choose to keep the annotations , but with far fewer harmful drawbacks compared to the EJB2 invasiveness .

 

What if there were four simple rules that you could follow that would help you create good
designs as you worked? What if by following these rules you gained insights into the structure
and design of your code
, making it easier to apply principles such as SRP and DIP?
What if these four rules facilitated the emergence of good designs?

 

According to Kent, a design is “simple” if it follows these rules:
• Runs all the tests
• Contains no duplication
• Expresses the intent of the programmer
• Minimizes the number of classes and methods

The rules are given in order of importance.

 

Tight coupling makes it difficult to write tests. So, similarly, the more tests we write,
the more we use principles like DIP and tools like dependency injection, interfaces, and
abstraction to minimize coupling. Our designs improve even more .

 

Remarkably, following a simple and obvious rule that says we need to have tests and
run them continuously impacts our system’s adherence to the primary OO goals of low
coupling and high cohesion
. Writing tests leads to better designs.

 

The majority of the cost of a software project is in long-term maintenance . In order to
minimize the potential for defects as we introduce change, it’s critical for us to be able to
understand what a system does.

 

Therefore, code should clearly express the intent of its author . The clearer
the author can make the code
, the less time others will have to spend understanding it. This
will reduce defects and shrink the cost of maintenance .

 

You can express yourself by choosing good names . We want to be able to hear a class
or function name and not be surprised when we discover its responsibilities.


You can also express yourself by keeping your functions and classes small . Small
classes and functions are usually easy to name, easy to write, and easy to understand.

 

You can also express yourself by using standard nomenclature . Design patterns, for
example, are largely about communication and expressiveness. By using the standard
pattern names, such as COMMAND or VISITOR, in the names of the classes that implement
those patterns, you can succinctly describe your design to other developers.

 

Well-written unit tests are also expressive. A primary goal of tests is to act as documentation
by example. Someone reading our tests should be able to get a quick understanding
of what a class is all about.

 

But the most important way to be expressive is to try . All too often we get our code
working
and then move on to the next problem without giving sufficient thought to making
that code easy for the next person to read
. Remember, the most likely next person to read
the code will be you
.

 

So take a little pride in your workmanship . Spend a little time with each of your functions
and classes. Choose better names, split large functions into smaller functions, and
generally just take care of what you’ve created
. Care is a precious resource.

 

Our goal is to keep our overall system small while we are also keeping our functions
and classes small. Remember, however, that this rule is the lowest priority of the four rules
of Simple Design.
So, although it’s important to keep class and function count low, it’s
more important to have tests , eliminate duplication , and express yourself .

 

Is there a set of simple practices that can replace experience? Clearly not . On the other
hand, the practices described in this chapter and in this book are a crystallized form of the
many decades of experience enjoyed by the authors. Following the practice of simple
design can and does encourage and enable developers to adhere to good principles and
patterns
that otherwise take years to learn .

 

 

 

 

  • 大小: 35.1 KB
分享到:
评论

相关推荐

    Clean.Code.Summary.B01AAS8T4A.pdf

    Chapter 1 Clean Code Chapter 2 Meaningful Names Chapter 3 Functions Chapter 4 Comments Chapter 5 Formatting Chapter 6 Objects and Data Structures Chapter 7 Error Handling Chapter 8 Boundaries Chapter ...

    24.Patterns.for.Clean.Code

    Robert lays out 24 patterns of thought and design that tend to produce faster, more reliable, and easier to maintain code without noticeably increasing the difficulty or decreasing the speed of coding...

    Clean Code

    But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to ...

    Learn.CakePHP.With.Unit.Testing.1484212134

    Accelerate your development of ...Chapter 12: Test Suites Chapter 13: Testing from Command Line Chapter 14: Goodies

    Practical.Swift

    This is the ideal guide to walk you through Xcode and all the latest features Swift 3 has to offer. If you have picked up this book, chances are you know a little ...Chapter 12: Grocery App: Finish Line

    cleancode4noobs:清洁代码摘要(PT-BR)

    CleanCode4Noobs 罗伯特·塞西尔·马丁(Robert Cecil Martin)编写的《清洁代码:敏捷软件技巧手册》的摘要。 内容 参考 Robert C. Martin,“清洁代码:敏捷软件Craft.io手册” 如何贡献 贡献使开源社区成为了一...

    Python.Crash.Course.A.Hands-On.Project-Based.Introduction.to.Programming

    Chapter 11: Testing Your Code Part II: Projects Project 1: Alien Invasion Project 2: Data Visualization Project 3: Web Applications Appendix A: Installing Python Appendix B: Text Editors Appendix C:...

    Apache.Maven.Cookbook.1785286129

    Over 90 hands-on recipes to successfully build and automate development life cycle tasks following Maven conventions and best practices About This Book ...Chapter 11: Advanced Maven Usage

    Clean Architectures in Python A practical approach to better software design

    The first chapter discusses briefly the components and the ideas behind this software structure, while chapter 2 runs through a concrete example of clean architecture for a very simple web service....

    Learn.Mobile.Game.Development.in.One.Day.Using.Gamesalad

    Chapter 12: Audio Chapter 13: The Expression Editor Chapter 14: Collisions and Physics Chapter 15: Camera Control and Graphical U Chapter 16: Game 3 – Box Breaker Chapter 17: Animation and Particles ...

    Web.Scraping.with.Python.Collecting.Data.from.the.Modern.Web

    Chapter 11. Image Processing and Text Recognition Chapter 12. Avoiding Scraping Traps Chapter 13. Testing Your Website with Scrapers Chapter 14. Scraping Remotely Appendix A. Python at a Glance ...

    C# Primer 中文版随书源码

    You may have to open your own, then copy in the form and code behind files. I’ll try to clean that up when I have time. The project listing under each chapter for this release looks as follows: ...

    R.Unleash.Machine.Learning.Techniques

    Chapter 12: Specialized Machine Learning Topics Module 3: Mastering Machine Learning with R Chapter 1: A Process for Success Chapter 2: Linear Regression – The Blocking and Tackling of Machine ...

    Less.Web.Development.Essentials.2nd.Edition

    Chapter 4: Testing Your Code And Using Prebuilt Mixins Libraries Chapter 5: Integrating Less In Your Own Projects Chapter 6: Using The Bootstrap 3 Frontend Framework Chapter 7: Less With External ...

    Test-.Driven.Python.Development.1783987928

    While exploring the common types of smelly code, we will go back into our example project and clean up the smells that we find. Additionally, we will use mocking to implement the parts of our ...

    ASP.NET.Web.API.and.Angular.2.17864

    This book covers all the major topics you need to create SPAs with ASP.NET Web API and Angular 2: routing, creating clean URLs, handling data (OData), and authentication Book Description For most ...

    Programming.Google.App.Engine.with.Java

    Because App Engine supports common Java API standards, your code stays clean and portable. Get a hands-on introduction to App Engine's tools and features, using an example application Simulate App ...

    Swift.by.Example.1785284703

    Whether you are an expert Objective-C programmer or new to this platform, you'll learn quickly, grasping the code of real-world apps to use Swift effectively. Prior experience in development for ...

    Rails.Angular.Postgres.and.Bootstrap.2nd.Edition

    Chapter 12. Wrangle Forms and Validations with Angular Chapter 13. Dig Deeper Appendix A1. Full Listing of Customer Detail Page HTML Appendix A2. Creating Customer Address Seed Data Appendix A3. How ...

Global site tag (gtag.js) - Google Analytics