Technical points
This article is not a boastful article and will not talk about many advanced architectures. On the contrary, it will explain many basic problems and writing problems. If readers think that basic problems and writing problems are not problems, please ignore this article and save time to do some meaningful things.
The backend management system + user applet implemented based on Spring Boot + MyBatis Plus + Vue & Element supports RBAC dynamic permissions, multi-tenant, data permissions, workflows, three-party login, payment, SMS, mall and other functions.
Project address:/YunaiV/ruoyi-vue-pro
Development Tools
I don’t know how many "old" programmers are still using Eclipse. These programmers either follow the old ways or don’t know the existence of other good development tools at all. The phenomenon of Eclipse eating memory lag and the various accidental and inexplicable abnormalities all tell us that it is time to find new development tools.
Replace IDE
I don’t want to explain what kind of IDE to change. If you want to become an excellent Java programmer, please change IntelliJ IDEA. The benefits of using IDEA are searched for Google.
Don't tell me that the shortcut keys are not easy to use
Replacing the IDE is not in the focus of my article, so I don’t want to spend too much space to write about why IDE is replaced. Here, I can only tell you that changing the IDE is just to write Java code better and faster. The reason is misleading.
Don't tell me that the shortcut keys are not easy to use, please try new things.
Based on the idea of microservices, the project practice is built in the B2C e-commerce scenario. The core technology stack is Spring Boot + Dubbo. In the future, Spring Cloud Alibaba will be reconstructed.
Project address:/YunaiV/onemall
Bean
Bean is one of the most used models. I will explain beans in large quantities, and I hope readers can experience it well.
domain package name
According to the "experience" of many Java programmers, a database table corresponds to a domain object, so when many programmers write code, the package name uses: . This writing seems to have become a constraint in the industry, and the database mapping object should be domain. But you are wrong. Domain is a domain object. Often when we do traditional Java software web development, these domains are all anemia models, without behavior, or without sufficient domain models. Therefore, in this theory, these domains should be an ordinary entity object, not a domain object, so please change the package name to:.
If you don’t understand what I said, please take a look at a book called “IMPLEMENTING DOMAIN-DRIVEN DESIGN” by Vaughn Vernon. The book explains the difference between anemia model and a domain model. I believe you will benefit a lot.
DTO
For data transmission, we should use DTO objects as the transmission object. This is what we agreed on, because I have been doing mobile API design for a long time. Many people have told me that they think that only when data is transmitted to the mobile phone (input or output), these objects become DTO objects. Please note! This understanding is wrong. As long as it is an object used for network transmission, we all think that they can be regarded as DTO objects. For example, in an e-commerce platform, users place an order and the order will be sent to the OMS or ERP system. The return value and entry parameters of these docking are also called DTO objects.
We agree that if an object is a DTO object, change the name to XXDTO, such as issuing an OMS: OMSOrderInputDTO.
DTO Conversion
As we know, DTO is a model object that interacts with the outside world. Then there will definitely be a step to convert the DTO object into a BO object or an ordinary entity object and let the service layer handle it.
Scene
For example, adding membership operations. Since it is used for demonstration, I only consider some simple data of the user. When the backend administrator clicks to add a user, he only needs to pass the user's name and age. After the backend receives the data, he will add three fields: creation time, update time and default password, and then save the database.
@RequestMapping("/v1/api/user") @RestController public class UserApi { @Autowired private UserService userService; @PostMapping public User addUser(UserInputDTO userInputDTO){ User user = new User(); (()); (()); return (user); } }
We will only focus on the conversion code in the above code. Please ignore other content:
User user = new User(); (()); (());
Please use the tool
Logically speaking, the above code is not a problem, but this way of writing is annoying to me. There are only two fields in the example. If there are 20 fields, how do we do it? Do you set data one by one? Of course, if you do this, there will definitely be no problem, but this is definitely not the best way to do it.
There are many tools online that support either shallow copy or deep copy Utils. For example, we can use #copyProperties to refactor and optimize the code:
@PostMapping public User addUser(UserInputDTO userInputDTO){ User user = new User(); (userInputDTO,user); return (user); }
It is a shallow copy method. When copying attributes, we only need to set the attribute values of the DTO object and the object to be converted to the same name and ensure the same type. If you use set to assign attributes when doing DTO conversion, please try this way to simplify the code and make the code clearer!
The semantics of transformation
Readers will definitely feel that the above conversion process is much more elegant after reading it, but when we write Java code, we need to consider semantic operations more, and then look at the above code:
User user = new User(); (userInputDTO,user);
Although this code simplifies and optimizes the code very well, its semantics are problematic. We need to withdraw a conversion process, so the code is changed to the following:
@PostMapping public User addUser(UserInputDTO userInputDTO){ User user = convertFor(userInputDTO); return (user); } private User convertFor(UserInputDTO userInputDTO){ User user = new User(); (userInputDTO,user); return user; }
This is a better semantic writing method. Although it is a little troublesome, its readability has greatly increased. When writing code, we should try to put the semantic levels similar to one method, such as:
User user = convertFor(userInputDTO); return (user);
Neither of these two pieces of code expose the implementation, and they are talking about how to do a set of semantic operations at the same level in the same method, rather than exposing the specific implementation.
As mentioned above, it is a reconstruction method. Readers can refer to Martin Fowler's "Refactoring Imporving the Design of Existing Code" (refactoring to improve the design of existing code) in this book.
Abstract interface definition
When the DTO conversion of several APIs is completed in actual work, we will find that there are many such operations, so an interface should be defined so that all such operations are carried out in rules.
If the interface is defined, the semantics of convertFor method will change, and it will be an implementation class.
Take a look at the abstract interface:
public interface DTOConvert<S,T> { T convert(S s); }
Although this interface is very simple, here we tell us something: to use generics. If you are an excellent Java programmer, please make generics for the abstract interface you want.
Let's look at the interface implementation:
public class UserInputDTOConvert implements DTOConvert { @Override public User convert(UserInputDTO userInputDTO) { User user = new User(); (userInputDTO,user); return user; } }
After we refactored this way, we found that the current code is so concise and so standardized:
@RequestMapping("/v1/api/user") @RestController public class UserApi { @Autowired private UserService userService; @PostMapping public User addUser(UserInputDTO userInputDTO){ User user = new UserInputDTOConvert().convert(userInputDTO); return (user); } }
review code
If you are a good Java programmer, I believe you should be like me, and have repeated reviews several times with your own code.
Let's look at this example of saving users. You will find that there are some problems with the return value in the API. The problem is that you should not directly return the User entity, because if this is the case, too much entity-related information is exposed. Such a return value is unsafe, so we should return a DTO object, which we can call UserOutputDTO:
@PostMapping public UserOutputDTO addUser(UserInputDTO userInputDTO){ User user = new UserInputDTOConvert().convert(userInputDTO); User saveUserResult = (user); UserOutputDTO result = new UserOutDTOConvert().convertToUser(saveUserResult); return result; }
This way your API is more sound.
I don’t know if readers have found that there are other problems after reading this code. As an excellent Java programmer, please take a look at this code we just abstracted:
User user = new UserInputDTOConvert().convert(userInputDTO);
You will find that it is unnecessary to convert new such a DTO, and each conversion object only appears when encountering a DTO conversion. So we should consider whether this class can be aggregated with DTO and take a look at my aggregation results:
public class UserInputDTO { private String username; private int age; public String getUsername() { return username; } public void setUsername(String username) { = username; } public int getAge() { return age; } public void setAge(int age) { = age; } public User convertToUser(){ UserInputDTOConvert userInputDTOConvert = new UserInputDTOConvert(); User convert = (this); return convert; } private static class UserInputDTOConvert implements DTOConvert<UserInputDTO,User> { @Override public User convert(UserInputDTO userInputDTO) { User user = new User(); (userInputDTO,user); return user; } } }
Then the conversion in the API is:
User user = new UserInputDTOConvert().convert(userInputDTO); User saveUserResult = (user);
Become:
User user = (); User saveUserResult = (user);
We added the conversion behavior to the DTO object. I believe that such an operation can make the code readable and conform to semantics.
Check the tool category again
Let’s look at the internal conversion code of DTO. It implements the DTOConvert interface we define ourselves, but there is really no problem in this way. Don’t you need to think about it anymore?
I don't think so. For the conversion semantics of Convert, many tool classes have such definitions. Convert is not an interface definition at the business level. It is just an interface definition for conversion attribute values between ordinary beans. Therefore, we should read more other codes containing Convert conversion semantics.
I carefully read the source code of GUAVA and found such a definition:
public abstract class Converter<A, B> implements Function<A, B> { protected abstract B doForward(A a); protected abstract A doBackward(B b); //Others}
From the source code, we can learn that Convert in GUAVA can complete forward and reverse conversion. Continue to modify this code converted in our DTO:
private static class UserInputDTOConvert implements DTOConvert<UserInputDTO,User> { @Override public User convert(UserInputDTO userInputDTO) { User user = new User(); (userInputDTO,user); return user; } }
After modification:
private static class UserInputDTOConvert extends Converter<UserInputDTO, User> { @Override protected User doForward(UserInputDTO userInputDTO) { User user = new User(); (userInputDTO,user); return user; } @Override protected UserInputDTO doBackward(User user) { UserInputDTO userInputDTO = new UserInputDTO(); (user,userInputDTO); return userInputDTO; } }
After reading this part of the code, you may ask, what is the use of reverse conversion? In fact, we have many small business needs, the incoming parameters and outgoing parameters are the same, so we can easily convert them. I will convert the UserInputDTO and UserOutputDTO mentioned above to UserDTO to show you.
DTO:
public class UserDTO { private String username; private int age; public String getUsername() { return username; } public void setUsername(String username) { = username; } public int getAge() { return age; } public void setAge(int age) { = age; } public User convertToUser(){ UserDTOConvert userDTOConvert = new UserDTOConvert(); User convert = (this); return convert; } public UserDTO convertFor(User user){ UserDTOConvert userDTOConvert = new UserDTOConvert(); UserDTO convert = ().convert(user); return convert; } private static class UserDTOConvert extends Converter<UserDTO, User> { @Override protected User doForward(UserDTO userDTO) { User user = new User(); (userDTO,user); return user; } @Override protected UserDTO doBackward(User user) { UserDTO userDTO = new UserDTO(); (user,userDTO); return userDTO; } } }
API:
@PostMapping public UserDTO addUser(UserDTO userDTO){ User user = (); User saveResultUser = (user); UserDTO result = (saveResultUser); return result; }
Of course, the above only shows the forward or reverse direction of the conversion direction. The DTO objects of the out parameter and incoming parameter of many business requirements are different, so you need to tell the program more clearly: the reverse direction cannot be called:
private static class UserDTOConvert extends Converter<UserDTO, User> { @Override protected User doForward(UserDTO userDTO) { User user = new User(); (userDTO,user); return user; } @Override protected UserDTO doBackward(User user) { throw new AssertionError("The reverse conversion method is not supported!"); } }
Take a look at the doBackward method and directly throw an assertion exception, not a business exception. This code tells the caller of the code that this method is not accurate to you. If you call it, I will "assert" your call is wrong.
For a more detailed introduction to exception handling, please refer to my previous article: How to design Java exceptions elegantly (/2016/04/28/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E8%AE%BE%E8%AE%A1java%E5%BC%82%E5%B8%B8/) should help you better understand exceptions.
Bean's verification
If you think the user API I wrote above is already perfect, it only means that you are not an excellent programmer. We should ensure that any data entry into the method is legal.
Why verify
Many people will tell me that if these APIs are provided to the front-end for calls, the front-end will verify them. Why do you still need to verify them?
Actually, the answer is this. I never trust anyone who calls my API or method, such as the front-end verification failed, or some people pass data directly into my API through some special channels (such as Charles for packet capture). Then I still perform normal business logic processing, and then it is possible to generate dirty data!
"It must be fatal to the generation of dirty data." I hope everyone keeps this sentence in mind. No matter how small the dirty data is, it may make you look for a few nights!
jsr 303 Verification
I think the jsr 303 implementation provided by hibernate is still very excellent at the moment. I don’t want to talk about how to use it, because you can search for many answers on Google!
Let’s explain the API instance that you are working at, and we are now checking the DTO data:
public class UserDTO { @NotNull private String username; @NotNull private int age; //Other codes are omitted}
API Verification:
@PostMapping public UserDTO addUser(@Valid UserDTO userDTO){ User user = (); User saveResultUser = (user); UserDTO result = (saveResultUser); return result; }
We need to pass the verification result to the front-end, and this exception should be converted into an API exception (an exception with error code).
@PostMapping public UserDTO addUser(@Valid UserDTO userDTO, BindingResult bindingResult){ checkDTOParams(bindingResult); User user = (); User saveResultUser = (user); UserDTO result = (saveResultUser); return result; } private void checkDTOParams(BindingResult bindingResult){ if(()){ //throw new Verification error exception with verification code } }
BindingResult is a result set after Spring MVC validates DTO. You can refer to the official spring documentation (/).
After checking the parameters, a "verification error exception with verification code" can be thrown. For the specific exception design, please refer to how to design the Java exception elegantly (/2016/04/28/%E5%A6%82%E4%BD%95%E4%BC%98%E9%9B%85%E7%9A%84%E8%AE%BE%E8%AE%A1java%E5%BC%82%E5%B8%B8/)。
Hug lombok
The above DTO code has made me very tired to read. I believe readers are the same. I am so annoyed to see so many Getter and Setter methods. Is there any way to simplify these at that time?
Please hug lombok, it will help us solve some problems that make us very upset
Remove Setter and Getter
Actually, I don’t really want to say this title because there are too many online, but because many people tell me that they don’t know the existence of lombok at all, so in order to help readers learn better, I am willing to write an example like this:
@Setter @Getter public class UserDTO { @NotNull private String username; @NotNull private int age; public User convertToUser(){ UserDTOConvert userDTOConvert = new UserDTOConvert(); User convert = (this); return convert; } public UserDTO convertFor(User user){ UserDTOConvert userDTOConvert = new UserDTOConvert(); UserDTO convert = ().convert(user); return convert; } private static class UserDTOConvert extends Converter<UserDTO, User> { @Override protected User doForward(UserDTO userDTO) { User user = new User(); (userDTO,user); return user; } @Override protected UserDTO doBackward(User user) { throw new AssertionError("The reverse conversion method is not supported!"); } } }
See, the annoying Getter and Setter methods have been removed.
But the above examples are simply not enough to reflect the power of lombok. I hope to write some use of lombok that is difficult to find online, or few people explain, and the semantic description of the program when using it.
For example: @Data, @AllArgsConstructor, @NoArgsConstructor..I won’t explain these one by one. Please check the information yourself.
Chain style in bean
What is chain style? Let me give you an example and see the following Student's bean:
public class Student { private String name; private int age; public String getName() { return name; } public Student setName(String name) { = name; return this; } public int getAge() { return age; } public Student setAge(int age) { return this; } }
Take a closer look at the set method. This setting is the style of chain. When calling, you can use it like this:
Student student = new Student() .setAge(24) .setName("zs");
I believe that using such chain code will bring good readability to more programs. Let’s take a look at how to use lombok to improve it, please use @Accessors(chain = true) and see the following code:
@Accessors(chain = true) @Setter @Getter public class Student { private String name; private int age; }
This completes a chain operation that is very friendly to beans.
Static construction method
The semantics and simplification of static constructors are really higher than going directly to a new object. For example, new List object, the past use was like this:
List<String> list = new ArrayList<>();
Take a look at how it is created in guava:
List<String> list = ();
Lists naming is a convention (as the saying goes: conventions are better than configuration). It means that Lists is a tool class of the List class. Then, using the tool class of List to generate List, is this semantics more direct than directly new subclass? The answer is yes. For example, if there is a tool class called Maps, did you think of a way to create a Map:
HashMap<String, String> objectObjectHashMap = ();
OK, if you understand the semantics I said, then you are one step closer to becoming a Java programmer.
Let’s look back at the Student just now. Many times, when we write the Student bean, it will have some fields that must be returned, such as the name field in the Student. The general way to deal with it is to wrap the name field into a constructor. Only by passing in a constructor such as name can a Student object be created.
Connect the above static construction method and the required parameters to be passed, and use lombok to change it to the following writing method (@RequiredArgsConstructor and @NonNull):
@Accessors(chain = true) @Setter @Getter @RequiredArgsConstructor(staticName = "ofName") public class Student { @NonNull private String name; private int age; }
Test code:
Student student = ("zs");
Is the semantics of bean constructed in this way much better than the direct new constructor with parameters (constructor with name).
Of course, after reading a lot of source codes, I want to believe that changing the static constructor ofName with of will be more concise first:
@Accessors(chain = true) @Setter @Getter @RequiredArgsConstructor(staticName = "of") public class Student { @NonNull private String name; private int age; }
Test code:
Student student = ("zs");
Of course, it still supports chain calls:
Student student = ("zs").setAge(24);
It is really concise to write code like this and very readable.
Using builder
I don't want to explain the Builder mode any more. Readers can take a look at the Builder mode of "Head First" (Design Mode).
What I want to talk about today is a variant builder model, that is, the builder model of building beans. In fact, the main idea is to take everyone to see what lombok has brought us.
Take a look at the original builder status of the Student class:
public class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { = name; } public int getAge() { return age; } public void setAge(int age) { = age; } public static Builder builder(){ return new Builder(); } public static class Builder{ private String name; private int age; public Builder name(String name){ = name; return this; } public Builder age(int age){ = age; return this; } public Student build(){ Student student = new Student(); (age); (name); return student; } } }
Call method:
Student student = ().name("zs").age(24).build();
Such builder code makes me feel disgusted, so I plan to refactor this code with lombok:
@Builder public class Student { private String name; private int age; }
Call method:
Student student = ().name("zs").age(24).build();
Agent Mode
As we know, calling the rest interface in a program is a common behavior. If you have used spring's RestTemplate like me, I believe you will be like me, and I hate the non-http status codes it throws very much.
So we consider designing the bottom-level wrapper of RestTemplate as the wrapper pattern:
public abstract class FilterRestTemplate implements RestOperations { protected volatile RestTemplate restTemplate; protected FilterRestTemplate(RestTemplate restTemplate){ = restTemplate; } //Implement all interfaces of RestOperations}
Then the extension class wraps the FilterRestTemplate:
public class ExtractRestTemplate extends FilterRestTemplate { private RestTemplate restTemplate; public ExtractRestTemplate(RestTemplate restTemplate) { super(restTemplate); = restTemplate; } public <T> RestResponseDTO<T> postForEntityWithNoException(String url, Object request, Class<T> responseType, Object... uriVariables) throws RestClientException { RestResponseDTO<T> restResponseDTO = new RestResponseDTO<T>(); ResponseEntity<T> tResponseEntity; try { tResponseEntity = (url, request, responseType, uriVariables); (()); (().name()); (()); }catch (Exception e){ (RestResponseDTO.UNKNOWN_ERROR); (()); (null); } return restResponseDTO; } }
The wrapper ExtractRestTemplate perfectly changes the behavior of exception throwing, making the program more fault-tolerant. Here we do not consider the functions completed by ExtractRestTemplate. Let us focus on FilterRestTemplate and "implement all interfaces of RestOperations". This operation is definitely not something that can be written in a short time. Before refactoring, I wrote it for almost half an hour, as follows:
public abstract class FilterRestTemplate implements RestOperations { protected volatile RestTemplate restTemplate; protected FilterRestTemplate(RestTemplate restTemplate) { = restTemplate; } @Override public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException { return (url,responseType,uriVariables); } @Override public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException { return (url,responseType,uriVariables); } @Override public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException { return (url,responseType); } @Override public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException { return (url,responseType,uriVariables); } //Other implementation code is omitted. . .}
I believe that after you read the above code, you will feel nauseous and nauseous like me. Later, I optimized my code with the proxy annotation provided by lombok (@Delegate):
@AllArgsConstructor public abstract class FilterRestTemplate implements RestOperations { @Delegate protected volatile RestTemplate restTemplate; }
These lines of code completely replace the verbose code mentioned above.
Isn't it very concise? Be a programmer who embraces lombok?
Reconstruction
Requirement case
Project requirements
During the project development stage, there is a requirement for placing an order and shipping: if an order is placed before 3 pm today, the delivery time is tomorrow. If an order is placed after 3 pm today, the delivery time is the day after tomorrow. If the determined time is Sunday, then another 1 day is added to this time as the delivery time.
Thinking and Reconstructing
I believe this requirement seems very simple and can be completed no matter how you write it.
Many people may see this requirement and start writing Calendar or Date for calculations to complete the requirement.
The advice I give is to carefully consider how to write code and then write it. It does not mean that all time operations are solved with Calendar or Date, but you must look at the scene.
For time calculation, we need to consider joda-time, a similar mature time calculation framework to write code, which will make the code more concise and easy to read.
Please consider how to complete this requirement with Java code, or write a thought you think of completing this code, and then look at my code below, so that you will gain more:
final DateTime DISTRIBUTION_TIME_SPLIT_TIME = new DateTime().withTime(15,0,0,0); private Date calculateDistributionTimeByOrderCreateTime(Date orderCreateTime){ DateTime orderCreateDateTime = new DateTime(orderCreateTime); Date tomorrow = (1).toDate(); Date theDayAfterTomorrow = (2).toDate(); return (DISTRIBUTION_TIME_SPLIT_TIME) ? wrapDistributionTime(theDayAfterTomorrow) : wrapDistributionTime(tomorrow); } private Date wrapDistributionTime(Date distributionTime){ DateTime currentDistributionDateTime = new DateTime(distributionTime); DateTime plusOneDay = (1); boolean isSunday = ( == ()); return isSunday ? () : () ; }
When reading this code, you will find that I treat the judgment and possible different results as a variable, and finally return it as a three-item operator. This elegance and readability are obvious. Of course, such code is not achieved overnight. I have optimized the above code generated by 3 times. Readers can compare their own code with the code I wrote.
Improvement method
If you have been a programmer for 3 years +, I believe that you can easily accomplish the requirements like the above, but if you want to be a programmer who can write Java, think carefully and refactor the code.
Writing code is like writing. Everyone can write the same words, but it is not certain whether it looks good or not. If you want to write a program well, you must constantly think and reconstruct, dare to try, dare to innovate, and do not follow the old ways. You must be an excellent Java programmer.
The best way to improve your code level is to refactor it in a organized manner! (Note: It is a organized reconstruction)
Design Pattern
Design patterns are tools, not indicators of whether you are a high-level programmer.
I often see a programmer shouting excitedly, "I use the design pattern for which program and which point, and how excellent it is written. When I looked through it carefully, I found that many of them were over-designed.
Business-driven technology or Technology-driven business
Business-driven technology or technology-driven business? In fact, this is a topic that has been debated, but many people don’t think so. I think it’s just that everyone is unwilling to admit it. Let me analyze with you how we should judge where we are as a Java programmer.
Business-driven technology: If your project is a project with little or no returns, please do not engage in other innovative things, and do not drive how to do business, but be familiar with what the pain points of the business are now? How to help the business make profits or make the project progress better and smoother.
Technology-driven business: If the project you are in is a very awesome, such as Taobao, I can communicate with the business while meeting the business needs and what kind of technology can better help the business create profits. For example, when placing an order, you have to be in the queue. The order status may be processed in a few minutes, but it will give users a smoother experience and earn more access traffic. Then I believe that the business is willing to be driven by technology and will agree to the delay issue of orders. This is technology-driven business.
I believe most people are still in the direction of business-driven technology.
So since you can't drive your business, please embrace business changes.
Code design
I have been working on Java backend projects, and there are often some changes, and I believe everyone has encountered them.
For example, when we write a piece of code, we consider mapping the requirements into the state mode of the code. Suddenly one day, a lot of behavior changes are added to the state mode. At this time, you scratch your head and you forcefully add too many behaviors and changes to the state mode.
Gradually you will find that these state modes are actually more like a cluster of algorithms. You should use the strategy mode, and you should be dizzy at this time.
Having said so much, I mean, as long as you think it is reasonable, please change the state mode to the strategy mode. All modes are not imagined out of thin air, they are all based on reconstruction.
There is no silver bullet in Java programming. Please embrace business changes and keep thinking about reconstruction, and you will have a better code design!
Are you really excellent?
I'm so sorry, I took such a boring title.
A popular programming method is called pairing programming abroad. I believe that many domestic companies have not done this. I will not talk about the benefits of pairing programming. In fact, it is a process of improving each other while code reviewing. Since you can't do this, how can you keep improving in your own world?
"When you are developing, you always think that the code you make is correct and the writing method is perfect." I believe this is the voice of most people, and you will return to the question just now. How can you continue to improve in your own world?
The answer is:
- Look at the source code of mature frameworks
- Look back at your code
- Diligent in reconstructing
Are you really excellent? If you complete the learning source code every week, look back at your own code, and then refactor it diligently, I think you are really excellent.
Even if you may just be just getting started, but you have been persisting, you are a programmer who can really write java code.
Skill
UML
I don’t want to discuss UML-related knowledge, but I think if you really know how to write Java, please learn to express yourself first. UML is the language you speak. To be an excellent Java programmer, please learn at least these two types of UML diagrams:
- Class diagram
- Timing diagram
clean code
I think keeping the code concise and readability is the most basic guarantee of the code. If one day reduces these two points for the efficiency of the program, I think it is understandable. Apart from that, there is no reason to let you squander your code at will.
- Readers can take a look at the book "Clean Code" published by Robert C. Martin
- You can refer to Meituan article to talk about clean code (/);
- You can also take a look at Alibaba's Java coding specifications (/articles/69327?spm=5176..1.om5dRN)。
Anyway, keep your code neat.
Basic Linux commands
This actually has nothing to do with being able to write Java, but Linux often does host containers running Java. Please learn the basic commands of Linux well.
Refer to Brother Niao's "Linux Private Vegetables"
Summarize
Java is a big system. Today's discussion does not involve the framework and architecture related knowledge, but only discusses how to write good code.
This article explains how to write Java programs from the small aspects to the large aspects, and tells readers how to improve their coding level.
This is the end of this article about sharing shocking Java code skills. For more related Java code skills, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!