Objective C # Principle 32: small and cohesive assembly)

Source: Internet
Author: User
Tags mscorlib

Objective C # Principle 32: small and cohesiveProgramSet
Item 32: prefer smaller, cohesive assemblies

This principle should actually be called: "An assembly of a reasonable size and a small number of common types should be created ". But this is too long, so it is named after the most common mistake I think: developers always put everything apart from the water gap in the kitchen, kitchen Sink may be a spoken word and cannot find out what it means, so it is literally translated .), Put them in one assembly. This is not conducive to reusing components, but also to updating small and medium parts of the system. Many small assemblies that exist in the form of binary components can make them easy.

However, this title is also eye-catching for assembly cohesion. The cohesion of an Assembly refers to the degree of responsibility from a conceptual unit to a single component. Aggregate components can be summarized in one sentence. You can see these in a lot of. Net FCL programs. There are two simple examples: the system. Collections assembly is responsible for providing the data structure for the ordered set of related objects, while the system. Windows. Forms Assembly provides the model of the Windows control class. Web form and Windows form are in different programming sets because they are irrelevant. You should describe your assembly in a simple sentence in the same way. Don't be fooled: A myapplication Assembly provides everything you want. Yes, this is also a simple sentence, but it is too lazy, and you are likely to use some of the content in my2ndapplication (I think you may want to reuse it. Here, "some of the content" should be placed in an independent program set .) The Assembly does not need to use all functions.

You should not use only one public class to create a program assembly. There should be a compromise. If you are too radical and have created too many assemblies, you will lose some of the advantages of using encapsulation: First, you lose the opportunity to use the internal types, an internal type is a public class unrelated to encapsulation (packaging) in a dataset (see Principle 33, restrict access outside the Assembly ). The JIT compiler can have a lot of inline efficiency in an assembly, which is much more efficient than shuttle between multiple sets. That is to say, it is good for you to place some related types in a set of programs. Our goal is to create the most appropriate Assembly size for our components. This goal can be easily achieved, that is, a component should have only one responsibility.

In some cases, an assembly is the binary representation of a class. We use classes to encapsulateAlgorithmAnd storage data. Only public interfaces can become "official" contracts, that is, only public interfaces can be accessed by users. Similarly, a collection provides Binary packages for the related classes. Except this Assembly, only the public and protected classes are visible. A tool class can be an internal class of an assembly. Indeed, they should have a wider access scope for private Nested classes, but you have a mechanism to share the internal implementation of the Assembly, instead of exposing this implementation to all users. That is, encapsulate the related classes and separate them from the program set into multiple programs.

In fact, the use of multi-assembly can make many different deployment options very simple. Consider a three-tier application. One part of the program is running in the form of a smart client, while the other part is running on the server. You provide some verification principles on the client to ensure that the data input and modification feedback are correct. On the server, you need to repeat these principles and combine some verification to ensure stricter verification. These server-side business principles should be a complete set, and each client is just a subset.

Indeed, you can also create different assemblies for the Business Principles of the client and the server by reusing the source files, but this will become a complicated problem for your deployment mechanism. When you update these business principles, you have two installations to complete. Instead, you can detach a portion of the verification from strict server-side verification and encapsulate it into different sets and place them on the client. In this way, you can reuse binary objects encapsulated into an assembly. Compared with reuseCodeOr resources, it is much better to re-compile to multiple assembly.

As a program, it should be an organizational structure library containing related functions. This is already familiar to everyone, but it is difficult to implement it in practice. In fact, for a distributed application, you may not know in advance which classes should be distributed to the server and client at the same time. Even if possible, the functions of the server and client may flow. You may have to deal with both sides in the future. By making the Assembly as small as possible, you may simply re-deploy the server and client. An assembly is the binary block of an application. For a working application, it is easy to add a new component plug-in. If you are not careful about any errors, creating too many assemblies is much easier to handle than creating too many programs.

I often think of the program set and binary components as Lego. You can easily extract a Lego and replace it with another one. Similarly, for an assembly with the same interface, you should be able to easily extract it and replace it with a new one. And other parts of the program should be able to run as usual. This is a bit like Lego. If all your parameters and return values are interfaces, any assembly can easily be replaced by another one with the same interface (see Principle 19 ).

A smaller assembly can also enable you to process the overhead during program startup in stages. Larger programs require more CPU time to load, and more time to compile necessary IL commands to machines. The JIT must only be required at startup, while the Assembly is fully loaded, and the CLR must save a stub for each method in the Assembly.

Take a break and make sure that we do not go to extremes. This principle is to ensure that you do not create a single monolithic circuit program, but create a binary-based overall system and reusable components. Do not follow this principle to go to another extreme. The overhead of a large application based on too many small sets is related. If your program uses too many assemblies, the inter-assembly shuttle will produce more overhead. When loading more assemblies and converting Il to machine commands, the CLR loader needs to adjust the function entry address.

Similarly, security checks become an additional overhead when inter-assembly shuttles. All codes in the same Assembly have the same level of trust (not the same level of access, but the same level of trust ). At any time, the CLR performs some security verification as long as the code access exceeds an assembly. The less time the program spends on the shuttle between the Assembly, the higher the efficiency of the program.

None of these performance-related descriptions discourage you from splitting a large assembly into a small assembly. Performance loss is the second. The design of C # And. NET is based on components. better scalability is usually more valuable.

So, how much code or classes do you decide to put in an assembly? More importantly, how do you decide which code should be in a program set? This depends largely on the actual application, so there is no such argument. I have a recommendation here: By observing all the public classes, we can use a public base class to merge these classes into a set of programs. Then add some tool classes to this Assembly. These tool classes are mainly responsible for providing the functions of all related classes. Encapsulate related public interfaces into an independent set of programs. The last step is to view the objects that are horizontally accessed in the application. These are candidates that may become widely used tool assembly and may be included in the tool library of the application.

The final result is that your components are only in a simple collection. This collection contains only some required public classes and some tool classes to support them. In this way, you create an assembly that is small enough, and it is easy to get the benefits from updates and reuse, while also minimizing the overhead related to multiple assembly. A well-designed cohesion component can be summarized in one sentence. For example, "common. Storage. dll is used to manage all offline user data caches and user settings ." Describes a low cohesion component. On the contrary, two components are made: "common. Data. dll manages offline data cache. Common. settings. dll manages user settings ." When you separate them, you may need to use a third-party component: "Common. encryptedstorage. DLL for local encrypted storage management File System Io ", so that you can independently update these three components.

Small, is a relative condition. Mscorlib. dll is about 2 MB, but system. Web. regularexpressions. dll is only 56kb. But they all meet small core design goals and reuse the Assembly: they all contain a set of related classes and interfaces. The difference in absolute size should be determined based on different functions: mscorlib. dll contains the underlying classes to be used in all applications. System. Web. regularexpressions. dll is special. It only contains some regular expression classes to be used in Web controls. In this case, two different types of components are created: one is small, while the large assembly is concentrated on special functions. The widely used Assembly contains common functions. In either case, they should be as small as possible until they cannot be smaller.
======================================

 

Item 32: prefer smaller, cohesive assemblies
This item shoshould really be titled "build assemblies that are the right size and contain a small number of public types. "But that's too wordy, So I titled it based on the most common mistake I see: developers putting everything but the kitchen sink in one assembly. that makes it hard to reuse components and harder to update parts of a system. extends Smaller assemblies make it easier to use your classes as binary components.

The title also highlights the importance of cohesion. cohesion is the degree to which the responsibilities of a single component form a meaningful unit. cohesive components can be described in a single simple sentence. you can see this in memory of. net FCL assemblies. two examples are: the system. collections Assembly provides data structures for storing sets of related objects and the system. windows. forms Assembly provides classes that model Windows controls. web forms and Windows forms are in different assemblies because they are not related. you shoshould be able to describe your own assemblies in the same fashion using one simple sentence. no cheating: The myapplication Assembly provides everything you need. yes, that's a single sentence. but it's also lazy, and you probably don't need all of that functionality in my2ndapplication (though you 'd probably like to reuse some of it. that "some of it" shocould be packaged in its own assembly ).

You shoshould not create assemblies with only one public class. you do need to find the middle ground. if you go too far and create too export assemblies, you lose some benefits of encapsulation: you lose the benefits of internal types by not packaging related public classes in the same assembly (see item 33 ). the JIT compiler can perform more efficient inlining inside an assembly than processing SS assembly boundaries. this means that packaging related types in the same assembly is to your advantage. your goal is to create the best-sized package for the functionality you are delivering in your component. this goal is easier to achieve with cohesive components: Each component showould have one responsibility.

in some sense, an assembly is the binary equivalent of class. we use classes to encapsulate algorithms and data storage. only the public interfaces are part of the official contract, so only the public interfaces are visible to users. in the same sense, assemblies provide a Binary Package for a related set of classes. only public and protected classes are visible outside an assembly. utility classes can be internal to the Assembly. yes, they are more visible than private Nested classes, but you have a mechanic to share common implementation inside that assembly without exposing that implementation to all users of your classes. partitioning your application into multiple assemblies encapsulates related types in a single package.

Second, using multiple assemblies makes a number of different deployment options easier. consider a three-tiered application, in which part of the application runs as a Smart Client and part of the application runs on the server. you supply some validation rules on the client so that users get feedback as they enter or edit data. you replicate those rules on the server and combine them with other rules to provide more robust validation. the complete set of business rules is implemented at the server, and only a subset is maintained at each client.

sure, You cocould reuse the source code and create different assemblies for the client and server-side business rules, but that wowould complicate your Delivery Mechanic. that leaves you with two builds and two installations to perform when you update the rules. instead, separate the client-side validation from the more robust server-side validation by placing them in different assemblies. you are reusing binary objects, packaged in assemblies, rather than reusing object code or source code by compiling those objects into the multiple assemblies.

An assembly shoshould contain an organized library of related functionality. that's an easy plattings, but it's much harder to implement in practice. the reality is that you might not know beforehand which classes will be distributed to both the server and client portions of a distributed application. even more likely, the set of server-and client-side functionality will be somewhat fluid; you'll move features between the two locations. by keeping the Assemblies small, you'll be more likely to redeploy more easily on both client and server. the Assembly is a binary building block for your application. that makes it easier to plug a new component into place in a working application. if you make a mistake, make too then Smaller assemblies rather than too few large ones.

I often use Legos as an analogy for assemblies and binary components. you can pull out one Lego and replace it easily; it's a small block. in the same way, you should be able to pull out one assembly and replace it with another assembly that has the same interfaces. the rest of the application shoshould continue as if nothing happened. follow the Lego analogy a little farther. if all your parameters and return values are interfaces, any assembly can be replaced by another that implements the same interfaces (see item 19 ).

Smaller assemblies also let you amortize the cost of application startup. the larger an assembly is, the more work the CPU does to load the Assembly and convert the necessary IL into machine instructions. only the routines called at startup are jited, but the entire Assembly gets loaded and the CLR creates stubs for every method in the Assembly.

Time to take a break and make sure we don't go to extremes. this item is about making sure that you don't create single monolithic programs, but that you build systems of binary, reusable components. you can take this advice too far. some costs are associated with a large program built on too except small assemblies. you will incur a performance penalty when program flow crosses assembly boundaries. the CLR loader has a little more work to do to load assemblies and turn il into machine instructions, and the special resolving function addresses.

Extra security checks also are done internal SS assembly boundaries. all code from the same assembly has the same level of trust (not necessarily the same access rights, but the same trust level ). the CLR performs some security checks whenever code flow crosses an assembly boundary. the fewer times your program flow crosses assembly boundaries, the more efficient it will be.

none of these performance concerns shoshould dissuade you from breaking up assemblies that are too large. the performance penalties are minor. C # And. net were designed with components in mind, and the greater flexibility is usually worth the price.

so how do you decide how much code or how many classes go in one assembly? More important, how do you decide which code goesin an assembly? It depends greatly on the specific application, so there is not one answer. here's my recommendation: start by looking at all your public classes. combine public classes with common base classes into assemblies. then add the Utility Classes necessary to provide all the functionality associated with the public classes in that same assembly. package related public interfaces into their own assemblies. as a final step, look for classes that are used horizontally using SS your application. those are candidates for a broad-based utility Assembly that contains your application's utility library.

the end result is that you create a component with a single related set of public classes and the utility classes necessary to support it. you create an assembly that is small enough to get the benefits of easy updates and easier reuse, while still minimizing the costs associated with multiple assemblies. well-designed, cohesive components can be described in one simple sentence. for example, "Common. storage. DLL manages the offline data cache and all user settings "describes a component with low cohesion. instead, make two components: "Common. data. DLL manages the offline data cache. common. settings. DLL manages user settings. "When you 've split those up, you might need a third component:" Common. encryptedstorage. DLL manages File System Io for encrypted local storage. "You can update any of those three components independently.

Small is a relative term. mscorlib. DLL is roughly 2 MB; system. web. regularexpressions. DLL is merely 56kb. but both satisfy the core design goal of a small, reusable Assembly: they contain a related set of classes and interfaces. the difference in absolute size has to do with the difference in functionality: mscorlib. dll contains all the low-level classes you need in every application. system. web. regularexpressions. DLL is very specific; it contains only those classes needed to support regular expressions in Web controls. you will create both kinds of components: small, focused assemblies for one specific feature and larger, broad-based assemblies that contain common functionality. in either case, make them as small as what's reasonable, but not smaller.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.