当前位置:网站首页>Some basic design knowledge
Some basic design knowledge
2022-06-13 00:23:00 【carl-zhao】
Reprinted address : Some basic design knowledge
Recently, I told some common sense of design to the new members of the team , It may also help other newcomers ,
Put a few items that come to mind for the time being , Let's write it down here .
1、API And SPI Separate
A framework or component usually has two types of customers , One is the user , One is the extender .
API(Application Programming Interface) It is for users , and SPI(Service Provide Interface) It is for the extender . In design , Try to isolate them , And don't mix it up , in other words , The user cannot see the implementation written by the extender .
such as :
1. One Web frame , It has one API The interface is called Action, There's a execute() Method , It is for users to write business logic . then ,Web The frame has a SPI The interface controls the output mode for the extender .
2. velocity Template output is still in json Output, etc , If this Web The framework uses an all - inheritance Action Of VelocityAction And a JsonAction As an extension , Use velocity The output of the template inherits VelocityAction, Use json Output inheritance JsonAction, This is it. API and SPI There is no negative example of separation .
SPI Interfaces are mixed API Interface , It's a reasonable way , There's a separate one Renderer Interface , Yes VelocityRenderer and JsonRenderer Realization , Web The framework will Action The output of is forwarded to Renderer Interface to render output .
Anyway, the example :
The right example :
2、 Service domain / Entity domain / Session domain separation
Any frame or component , There will always be a core domain model , such as :
Entity domain : image Spring Of Bean,Struts Of Action,Dubbo Of Service,Napoli Of Queue wait . This core domain model and its components are called entity domains , It represents the goal we want to operate on , Entity domains are usually thread safe , Whether through invariant classes , sync , Or copy .
Service domain : That is, the behavior domain , It is the function set of the component , It is also responsible for the lifecycle management of entity domain and session domain . such as Spring Of ApplicationContext,Dubbo Of ServiceManager etc. , Service domain objects are usually heavy , And it's thread safe , And serve all calls with a single instance .
Session domain : It is an interactive process , The important concept in conversation is context , What is context ? Let's say :“ See you in the old place ”, there “ Old Place ” Context information , Why do you say “ Old Place ” The other person will know , Because we defined “ Old Place ” Specific content of , So , Context usually holds the state variables in the interaction process , The session object is usually light , Each request recreates the instance , Destroy after request .
In short :
Leave the meta information to the entity domain , The temporary state in a request is held by the session domain , The service domain runs through the whole process .
two Kind of example Son
3、 Set the interception interface on the important process
- If you want to write a remote call framework , The remote calling process should have a unified interception interface ;
- If you want to write one ORM frame , At least SQL Implementation process of ,Mapping The process should have an interception interface ;
- If you want to write one Web frame , The request execution process should have an interception interface ;
No common framework can Cover Live with all the needs , Allow external behavior , Is the basic extension of the framework .
- If someone wants to make a remote call , Verify the command board , Verify the black and white list , Count the logs ;
- If someone wants to be in SQL Add pagination wrapping before execution , Do data permission control , Statistics SQL execution time ;
- If someone wants to check the role before the request is executed , The input / output stream under the packaging , Count the number of requests ;
wait , You can do it yourself , Without intruding into the frame . Interception interface , Usually, the process itself is encapsulated by an object , To the interceptor chain .
such as : The remote calling main procedure is invoke(), The interceptor interface is usually invoke(Invocation),Invocation Object encapsulates the context in which the procedure is to be executed , also Invocation There's one in it invoke() Method , The interceptor decides when to execute . meanwhile ,Invocation It also represents the interceptor behavior itself , So the last interceptor Invocation In fact, it is the process of packaging the next interceptor , Until the last interceptor Invocation It is the final of packaging invoke() The process , Empathy ,SQL The main process is execute(), The interceptor interface is usually execute(Execution), The principle is the same , Of course , The implementation method can be arbitrary , The above is just an example .
4、 Important state changes send events and leave listening interfaces
Here is the difference between an event and the interceptor above :
Interceptor : Is the process of intervention , It's part of the process , It's based on process behavior .
event : Is based on status data , The same state of any behavior change , The events should be consistent , Events are usually notified afterwards , It's a Callback Interface , Method names are usually past tense , such as onChanged().
For example, the remote call framework , An event should be sent when the network is disconnected or connected , When an error occurs, you can also consider sending an event , In this way, it is possible for peripheral applications to observe changes within the framework , Adapt accordingly .
5、 The responsibilities of the extension interface shall be as single as possible , It has composability
such as , The protocol of the remote call framework can be replaced , If only one general extension interface is provided , Of course, switching protocols can be achieved , But protocol support can be subdivided into low-level communication , serialize , Dynamic proxy, etc , If the interface is disassembled , Orthogonal decomposition , It will be easier for the extender to reuse the existing logic , Instead, it just replaces some part of the implementation strategy , Of course, the granularity of this decomposition needs to be well grasped .
6、 Micronucleus plug-in , Treat third parties equally
A good framework for development , We all follow the concept of micronucleus
Eclipse My micronucleus is OSGi, Spring My micronucleus is BeanFactory,Maven My micronucleus is Plexus.
Usually the core should not be functional , It is a lifecycle and integration container , In this way, all functions can interact and expand in the same way , And any function can be replaced , If you can't do micronucleus , At least treat third parties equally , That is, the functions that the original author can realize , The extender should be able to do it all by extension , The original author should regard himself as an extender , Only in this way can the sustainability and stability of the framework be ensured .
7、 Do not control the lifecycle of external objects
Like the above Action Use interfaces and Renderer Extension interface , If the framework allows users or extenders to Action or Renderer The class name or class meta information of the implementation class is reported . And then internally through reflection newInstance() Create an instance , So the framework controls Action or Renderer Implement the life cycle of the class , Action or Renderer Life, old age and death of , All the frames have been made by themselves , External expansion or integration can do nothing .
A good idea is to let users or extenders put Action or Renderer An instance of the implementation class is reported , The framework only uses these instances , How these objects are created , How to destroy , It has nothing to do with the framework , At most, the framework provides tools to assist management , Not absolute control .
8、 Configurable must be programmable , And keep friendly CoC Appointment
Because there are many uncertain factors in the use environment , Frameworks always have some configuration , It usually comes to classpath Directly scan the configuration of a specified name , Or you can specify the configuration path at startup , As a general framework , What can be done with the configuration file must be done by programming , Otherwise, when users need to integrate your framework with another framework, it will bring a lot of unnecessary trouble .
in addition , Try to make a standard agreement , If the user does something according to a certain agreement , This configuration item is not required . such as : Configure template location , You can make an appointment , If you put it in templates There is no need to configure under the directory , If you want to change the directory , Just configure it .
9、 Distinguish between commands and queries , Define pre and post conditions
This is part of contractual design , Try to follow the method that has a return value is the query method ,void The way to return is the command , Query methods are usually idempotent , No side effects , That is not to change any state , transfer n The results are the same . such as get A property value , Or query a database record .
Command is something that has side effects , That is, the status will be modified , such as set A certain value , or update A database record , If your method changes the State , Then I did a query and returned , If possible , Split it into two methods of write read separation .
such as :
1. User deleteUser(id), Delete the user and return the deleted user , Consider changing to getUser() and void1 Of deleteUser().
2. in addition , Each method tries to pre assert the legitimacy of the incoming parameters , The validity of the returned result of the post assertion , And documented .
10、 Incremental expansion , Instead of extending the original core concepts
There are more and more products on our platform , The product has more and more functions , The products of the platform are designed to adapt to various BU And the needs of departments and product lines . It is bound to bring together many irrelevant functions , Customers can selectively use , To accommodate more requirements , Each product , Every frame , Are constantly expanding , And we often choose some extension methods , That is to extend the old and new functions into a common implementation .
What I want to discuss is , In some cases, the incremental expansion method can also be considered , That is, keep the simplicity of the original function , New functions are implemented independently . I have been working on the development of distributed service framework recently , Just make fun of the problems in our project .
such as : Remote call framework , There must be serialization , The function is very simple , Is to turn the flow into an object , Object to stream , But it may be used in some places osgi, When serializing like this ,IO Where ClassLoader May be related to the business party ClassLoader It's isolated , You need to convert the stream to byte[] Array , And then passed to the business party ClassLoader serialize .
In order to adapt osgi demand , Put the original non osgi And osgi The scene of is expanded , such , Whether or not osgi Environmental Science , Will be transferred into byte[] Array , Copy once . However , Most scenes don't use osgi, But for osgi Paid a price , If the incremental expansion mode is adopted , Not osgi The code is intact , Add one osgi The implementation of the , Use osgi When , Directly dependent on osgi It can be realized .
Another example : In the beginning , Remote services are based on interface methods , For transparent calls , such , The extension interface is ,invoke(Method method, Object[] args), later , There is a need for no interface calls , Even if there is no interface method, it can be called , And will POJO Objects are converted to Map Express , because Method Objects are not directly new Coming out , We unconsciously chose an extensible extension , Change the extension interface to invoke(String methodName, String[] parameterTypes, String returnTypes, Object[] args), This results in no matter whether or not there is no interface call , All of them have to be cleaned up parameterTypes from Class[] Turn into String[].
If you choose incremental expansion , Keep the original interface unchanged , Add one more GeneralService Interface , There is a general purpose invoke() Method , The same way as other interfaces in normal business , There is no need to change the extension interface , It's just GeneralServiceImpl Of invoke() The implementation will forward the received call to the target interface , In this way, the new functions can be added to the old functions , And keep the original structure simple .
Another example is : Stateless message sending , It's simple , Just serialize an object and send it , Later, there was a need to send synchronous messages , Need one Request/Response Pairing , Adopt extensible expansion , Naturally think of , A stateless message is actually a no Response Of Request, So in Request Riga boolean state , Indicates whether to return Response, If there is another session message sending requirement , Then add another Session Interaction . And found that , It turns out that synchronous message sending is a special case of session messages , All the scenes are passed on Session, Unwanted Session Just ignore the place . If you use incremental expansion , Stateless messages are sent intact .
Synchronous message sending , Add a to the stateless message Request/Response Handle ,
Session message sending , Add one SessionRequest/SessionResponse Handle .
边栏推荐
- 浏览器缓存的执行流程
- [matlab] 3D curve and 3D surface
- Packaging and uplink of btcd transaction process (III)
- 1115. alternate printing foobar
- Leaflet that supports canvas Path. Dashflow dynamic flow direction line
- The whole process from entering URL to displaying page (interview)
- Information collection for network security (2)
- 安全事故等级划分为哪几级
- 中科大USTC:Minrui Wang | 基于Transformer的多智能体强化学习的配电网稳压
- Masa auth - overall design from the user's perspective
猜你喜欢
Is the revised PMP worth testing?
一篇文章学会子网划分
Kaust:deyao Zhu | value memory map: a graph structured world model based on off-line reinforcement learning
MASA Auth - 从用户的角度看整体设计
Using com0com/com2tcp to realize TCP to serial port (win10)
【HCIE论述】STP-A
What are the PMP scores?
63. different paths II
String类中split()方法的使用
【Matlab】符号计算
随机推荐
测试平台系列(97) 完善执行case部分
PLC can also make small games ----- CoDeSys can write small games of guessing numbers
[LeetCode]14. Longest common prefix thirty-eight
[C] Inverts the binary of a decimal number and outputs it
PLC也能制作小游戏----Codesys编写猜数字小游戏
如何快速查询手机号码归属地和运营商
What are the PMP scores?
USTC of China University of science and technology: Minrui Wang | distribution network voltage stabilization based on transformer Multi-Agent Reinforcement Learning
【Matlab】多项式计算
2022-06-13日报: 图灵奖得主:想要在学术生涯中获得成功,需要注意哪些问题?
The PMP examination time in March 2022 is set -- "March 27"
Apispace empty number detection API interface is free and easy to use
Several interview questions in TCP three grips and four swings
Converting Chinese numbers to Arabic numbers in Delphi
Handling method of wrong heading of VAT special invoice
63. different paths II
1115. alternate printing foobar
Go design concurrent web crawler
RCC clock configuration of stm32f401
Five mock technologies of go