Use code to explain why you need an extension-oriented design

Use code to explain why you need an extension-oriented design

Use code to explain why you need an extension-oriented design

In basic object-oriented programming, you can only directly call the methods of a class, and these methods are defined by the author of this class, which is no problem for user-oriented classes. In addition, 20-30 years ago, before large standard libraries and open source libraries were reused, most of the code usually worked with the classes in your own code-that is, maintained by your own team or company Code. However, in the modern code world, we often use classes written by others.

Business logic usually uses a lot of standard library functions including strings and collections, as well as some classes in third-party libraries. We are limited by the operations provided by these classes. For example, when we need to replace spaces in a string with dashes, we write code like this:

string.replace(' ', '-')

But when we need to align the string on the left to a specified length, we may not have a ready-made method available. In these old languages ​​(such as Objective-C, C++, Java or JS), you need to force it to be written in this form :

leftPad(string, ' ', length)

This leftPad may come from a separate library¹, or it may come from a third-party tool function collection (such as Apache Commons), or you may write it yourself in your own project. In short, its call looks very different from the built-in methods on the string class.

Why is there such a problem? I quote Guy Steele, one of the authors of Java, a passage from his 1998 paper "The Language of Growth"².

In most languages, users can at least define some new grammars to represent another piece of code, and then can easily call these codes, this way can make the new grammar look like a native call. In this way, the user can build a larger language to meet his needs.
Guy Steele, Growing a Language

He is criticizing the lack of such facilities in APL, but the same criticism applies to old object-oriented languages ​​in modern environments. You are trapped in the operational vocabulary of a class, and this vocabulary is conceived by the designers of the original library, and it cannot be extended by you. In addition, it cannot be arbitrarily expanded by the maintainers of the widely used library, again citing the content of the same paper as the reason.

Part of the programming vocabulary is suitable for all programmers, but other parts are only suitable for a few people. Programmers need to understand and learn all their vocabulary usage, which is not fair.

Modern languages ​​(such as C#, Scala, Rust, Kotlin, and Swift) solve this problem by supporting extension methods. You can add domain-specific extension methods to classes that are not under your control, so that your own functions can be called similar to built-in methods, and your code can still be like prose, smoothly from left to right. read.

string.padLeft(' ', length)

The padLeft extension can be defined anywhere, it is a good story of the evolution of programming languages. However, its significance does not stop there.

Once a programming language supports extension functions, it changes the classic object-oriented API design method. This is a great revelation for a programmer who switched from an old language like Java to a modern language like Kotlin, because extension functions are usually only presented as convenient syntactic sugar³. Let's first look at an interface with a bunch of properties (or getter methods).


interface Obscure {
    val foo: Int
    val bar: Int
    val sum: Int
    val max: Int
    val min: Int
}

It is not much different from the interface or class you find in a typical business application-there are a bunch of properties and methods.

Can you quickly grasp what kind of entity this interface represents? What are the attributes of its state space? Without additional documentation, it is not easy to figure this out. But let's restructure this interface into a core entity and convenient extension functions.


interface NotObscure {
    val foo: Int
    val bar: Int
}

val NotObscure.sum: Int
val NotObscure.max: Int
val NotObscure.min: Int

Now, it is obvious that the core function of this interface is composed of two integer attributes foo and bar, while the remaining sum, max, and min attributes are only provided for convenience and are calculated on the basis of these core attributes. There is no need to explicitly document this difference-it can be seen directly from the structure of the code.

This extension-oriented design has been widely used in Kotlin standard libraries and third-party libraries. It is a powerful design technique, using it will have very good results.

This design method has a side effect. You may notice that Kotlin code usually uses wildcard import, such as import com.examplease.*. This is convenient in Kotlin, because it is very rare to import only one class in Kotlin. All useful, convenient, and practical functions are usually defined in the same package, but defined as extension functions outside the class.

Links in the article:

https://www.theregister.co.uk/2016/03/23/npm_left_pad_chaos/ How one developer just broke Node, Babel and thousands of projects in 11 lines of JavaScript, Chris Williams, 2016
https://www.cs.virginia.edu/~evans/cs655/readings/steele.pdf Growing a Language, Guy Steele, 1998
https://kotlinlang.org/docs/reference/extensions.html Extensions in Kotlin Programming Language

Original English:
https://medium.com/@elizarov/extension-oriented-design-13f4f27deaee

Reference reading:

  • Grab fuse design: how to deal with sudden peak rides
  • Netflix cloud native microservice design analysis
  • The right way to clean architecture
  • Several rules of code review
  • Exploring the solution for complex timing tasks: distributed task scheduling system

The author of this article, Roman Elizarov, is the head of the JetBrains Kotlin Library team. It is translated by high-availability architecture, technical originality and architecture practice articles. Welcome to submit articles through the official account menu "Contact Us".

Highly available architecture

Changing the way the internet is built

Use code to explain why you need an extension-oriented design

Guess you like

Origin blog.51cto.com/14977574/2546125