This is the third day of my participation in the August More text Challenge. For details, see: August More Text Challenge
97- Things – Every -x-should-know
License: Licensed BY CC BY-SA 3.0.
Welcome to like, bookmark and comment ~ O(∩_∩)O
-
This melon does not translate word for word, but take its essence, understanding abstract, combined with their own writing expression, and share with you. Recognize good programming concepts, to be excellent ~
-
The Path to Excellence: Learning 97 Good Programming Concepts (part 1)
-
The Path to Excellence: Learning 97 Good Programming Concepts (part 2)
Clean build
Do you get a string of warnings ⚠ when you build a project?
You do know you should fix it, but the project is still running, no time now, next time QAQ
But! As the code base grows, these warnings start to pile up, and when there are enough of them, you can’t find a single warning among the hundreds that you really want to read and fix.
In order for warnings to be useful, we must use a zero-tolerance policy for warnings generated by the build. Even if the warning is not important, does not affect the operation, does not affect the production line, but also to fix it!
Having a clean build makes it easier for someone else to take over my job, otherwise they wouldn’t be able to separate the important from the ignored warnings.
We believe that handling warnings in a build is the same as refactoring code. Instead of waiting for the last big clean up or refactoring, we should increase the frequency and granularity of processing to make the code go further
Command line operation
Nowadays, we are basically with the help of various development integration tools (IDE) for development, they bring enough convenience, reduce the program ape to each link of the careful thinking burden, with it!
However, there is a downside to ease of use: we don’t know what the IDE actually does, and the magic happens just by clicking and clicking buttons
If we use the command line, we will have a clearer idea of all the steps of the executable (such as compilation, assembly, linking, etc.).
You can use open source command-line tools, such as GCC, or use tools provided by a proprietary IDE. After all, a well-designed IDE is just a graphical front end to a set of command lines.
If you’re used to using the command line, you’ll find that it’s more powerful than an IDE. Since the IDE is a graphical front end for a specific set of command lines, stepping out of the IDE means that you can do all kinds of custom commands, such as grep and sed, that provide search and replace capabilities more powerful than the IDE.
Of course, this is not to tell you to give up using an IDE, just a suggestion: once in a while, get out of the IDE and use the command line, you might find new things
Proficiency in two or more languages
Every programmer starts by learning a programming language that dominates the way they think. No matter how many years of experience you have in this language, if you only know this language, your thinking will always be limited by this language.
And learning a second language can present challenges, especially if the language has a different paradigm than the first language. C, Pascal, Fortran, have the same paradigm. Switching from Fortran to C will not be too difficult, but if you move from Fortran to C++, it will be a huge challenge, as will the C++ to Haskell
We can list many programming paradigms: procedural, object-oriented, functional, logical, data flow, and so on.
Taking on challenges is good for you! Cross knowledge can make you more professional! Problems that cannot be solved in one language can easily be solved in another!
The crossover of programming languages has a huge impact. Anyone proficient in functional programming can easily apply declarative methods to make programs shorter and easier to understand.
Every programmer should be proficient in at least two different paradigms, and preferably all five of the above paradigms.
Learn a new language as a part-time job. It’s bound to pay off in the end!
Spend more time learning about ides
In the 1980s, syntax highlighting was a luxury, formatting tools were external tools, and debuggers were separate programs;
In the 1990s, companies began to see greater benefits in providing better tools for programmers. Integrated development environments (ides) began to grow, and graphical interfaces and mice became popular, making it easy for developers to click through menus.
Ides have become so common in the 21st century that many are free to use, making it easy to modify code and build projects.
Another amazing feature of modern ides is the ability to customize code rules, which makes team development more formal.
One of the not-so-good things about modern ides is that they don’t require a lot of effort to learn them, which leads us to recognize them only within their capabilities.
Learning IDE shortcuts is also important, and I recommend you spend more time researching how to use an IDE to work more effectively
Know your limits
“Man’s got to know His limitations.” — Dirty Harry
Man must know his limitations!
Resources are limited, you only have so much time, so much money, so much effort, so much intelligence…… Respecting these limitations is the foundation of everything.
For software engineers, too, recognize that the architecture and performance characteristics of a system have their limitations.
The complexity of software analysis is at an abstract level, but the software runs on real machines.
Modern computer systems are divided into two hierarchies of physical and virtual machines, including language runtimes, operating systems, CPUS, caches, random access memory, disk drives, and networks.
The following table shows the random access time and storage capacity limits for a typical networked server.
access time | capacity | |
---|---|---|
register | < 1 ns | 64b |
cache line | 64B | |
L1 cache | 1 ns | 64 KB |
L2 cache | 4 ns | 8 MB |
RAM | 20 ns | 32 GB |
disk | 10 ms | 10 TB |
LAN | 20 ms | > 1 PB |
internet | 100 ms | > 1 ZB |
Algorithms and data structures also differ in how efficiently they use caching:
Elements | Search time (ns) | ||
---|---|---|---|
Linear search | Binary search of sorted arrays | Search the van Emde Boas tree | |
8 | 50 | 90 | 40 |
64 | 180 | 150 | 70 |
512 | 1200 | 230 | 100 |
4096 | 17000 | 320 | 160 |
Know your next submission
The author tapped the three programmers on the shoulder and asked them what they were doing:
The first one says, “I’m reconstructing the methods”;
The second one says, “I’m adding some parameters to this network operation”;
A third said, “I’m studying this user’s behavior.”
While the first two seem more engrossed in the details of their work, the third has a bigger picture. The first two are very clear about which files will be changed and should be done in an hour or so. The third programmer is going to do it in a few days, maybe adding some classes, maybe modifying the service……
The third programmer’s biggest problem was that there was no decomposition, the task was too granular.
If the task situation changes, the first two can abandon their changes and start over. But the third will be reluctant to throw it all away because the code has been changed too much at once, leaving a legacy of bad code.
Know what your next submission is! If you can’t finish it, please fix it in time.
Large interconnected data belongs to databases
Once you’ve mastered SQL, writing database-centric applications can be a joy (which I haven’t done yet).
Once the properly normalized data is stored in the database, you can easily query the data using readable SQL without writing any complex code.
Similarly, a single SQL command can perform complex data changes. For one-time changes, such as changing the organization of persistent data, you don’t even need to write code: just start the database’s direct SQL interface.
This same interface also allows you to do test queries, avoiding the usual compile-to-edit, compile-to-compile cycle of programming languages.
Advanced database systems can even take advantage of multi-core processors behind the scenes. And, as technology improves, so does the performance of your application.
Learning to communicate
Programmers need a lot of communication.
In general, we communicate more with our computers, but we also communicate with our colleagues.
Today’s big projects are more social endeavors than just the application of programming techniques.
In addition to interacting with machines, selves, and peers, a project has many stakeholders, most of whom have different or no technical backgrounds, including testing, quality inspection, deployment, marketing, sales, different groups of users, and so on.
It’s almost impossible to get into their territory if you don’t speak their language.
If you talk to an accountant, you need to know the basics of central accounting, fixed capital, used capital, etc. If you talk to marketers or lawyers, you should be familiar with some of their jargon and language (and their thinking).
All of these domain-specific languages need to be mastered by someone on the project, preferably a programmer. Programmers are responsible for turning ideas into reality through computers.
Of course, life is more than software projects. To know another language is to have another soul, as Charlemagne said.
Whereof one cannot speak, thereof one must be silent. – Ludwig Wittgenstein
Learn to estimate
As a programmer, you need to constantly evaluate your tasks and provide them to your manager, colleagues, or users so that they have an accurate idea of the time, cost, technology, or other resources required to achieve your goals.
In order to be able to estimate well, it is obviously important to learn some estimation techniques.
This is not an uncommon conversation between a project manager and a programmer:
Project manager: Can you estimate how long it will take to develop feature XYZ?
Programmer: A month.
Project manager: Too long! We only have one week!
Programmer: At least three weeks.
Project Manager: I can give you two at most.
Programmer: clinch a deal!
There are three key definitions in this dialogue: estimate, goal, and commitment
- An estimate is a value, number, quantity, or approximate calculation or judgment of the degree of something. It is a factual measure based on hard data and past experience. For example: The development task is estimated to last 234 days;
- A goal is a statement of judgment about the desired implementation, e.g., the system must support at least 400 concurrent users;
- A promise is a promise that a specific feature will be available by a certain date or at a certain level of quality, e.g., the search feature will be available in the next release of the product;
What project managers really need from programmers is commitment to goals, not estimates.
Hello, World
Hello, World is what we started with.
The authors share this example:
He encountered a difficult problem and asked a colleague who was an expert in solving the problem. Instead of doing anything clever, the colleague solved the problem by taking the problem code out of a larger project and testing it.
Yes, maybe we’ve been working on a big project for too long, and it’s really hard to deal with a complex problem that can’t be reduced to an original problem.
Return to local, return to the command line, return to small items, return to the original code:
#include <stdio.h>
int main()
{
printf("Hello, World\n");
return 0;
}
Copy the code
Let the project speak
Your project may have a version control system connected to a continuous integration server that can automate tests to verify correctness.
Continuous integration can help you get a lot of build information. If you want your test coverage to be at least 20%, you can delegate this task to the project itself, and if it doesn’t meet this target, it will alert and produce a report.
You need to give your project a voice.
You can do this by email or instant messaging, notifying developers of the application’s status. It can also be applied to projects through the use of feedback devices (XFD).
The XFD principle is based on the results of automatic analysis to drive physical devices such as lights, portable fountains, toy robots, and even USB rocket launchers. Every time you break the limit, the device changes its state, lights turn on, you can hear build breaks, and you can even be programmed to smell code
If you put one of these devices in your project manager’s office to showcase the health of the entire project, he will be very grateful to you!
Let your project speak for itself, and the wonder speaks for itself.
Linkers are not magic
Many programmers recognize that the process of going from source to executable is:
- Edit source code;
- Compile source code into object files;
- Something amazing happened;
- Run executable files;
The author has been asked this question for decades in tech support:
- The linker indicates that the def is defined more than once;
- The linker indicates that ABC is an unparsed symbol;
- Why is my executable so big?
Followed by “What do I do now?” “And” as if “and” for some reason.”
Actually, there’s no magic to it, and the linker is a very stupid, simple, straightforward program.
All it does is link the code and data parts of the object file together, link the symbol reference to its definition, extract the unparsed symbol from the library, and write an executable file. And nothing more.
No spells! No magic!
The author is struggling to answer questions about the linker itself, which is not very complicated. Some of the questions seem very complicated, but they are actually younger ones, provided we understand the mechanism.
Persistence of temporary solutions
Why do we have temporary solutions?
Often there are immediate issues that need to be addressed, either from within the development team to fill in some gaps in the tool chain, or from outside to address some missing functionality.
We sometimes adopt temporary solutions that are useful but have an impact on code standards (as mentioned in the first point in this series).
There is always a temporary solution, which may not be consistent with the recognized production quality, but it has the advantage of solving the problem quickly.
What should we do?
- Avoid temporary solutions;
- Change the project manager’s temporary decision;
- 1. To remain as is;
If your project is so chaotic that it stops frequently, you need to think hard about the relationship between interim solutions and project standards.
May you have the peace to accept the things you cannot change and the courage to change the things you can.
Interface design
One of the most common tasks in software development is to develop interface specifications.
Interfaces include the highest level of abstraction (user interface), the lowest level of abstraction (function interface), and levels in between (class interface, library interface, and so on).
Whether you’re working with users to specify how they will interact with the system, working with developers to specify apis, or declaring private functions for classes, interface design is an important part of the job.
A good interface is:
-
Getting it right is easy: in a good GUI, we can always click the right icon, button, or menu item because it’s obvious and easy. In the API, the same is true, passing the right parameters with the right values is most natural;
-
Using errors is hard: a good GUI anticipates the mistakes people are likely to make and makes them harder to make. For example, disable or remove commands that don’t make sense in the current context, or the API eliminates the argument ordering problem by allowing arguments to be passed in any order;
Remember that interfaces exist for the convenience of the user, not the creator.
Carefully designed invisibility
One of the principles of software design — transparent mechanism and information hiding.
Google’s home page is pretty neat, but what’s going on behind the scenes when you’re trying to retrieve a piece of information is very complex.
Ten percent is shown to the user and the other 90 percent is hidden. One of the benefits of this is that your project has more space to work on because the user can’t see it; On the downside, users may think you’re not making any progress, or that there’s a lack of significant updates.
Invisibility can be dangerous! Explicit representations can convince people that progress is real rather than illusory, intentional rather than unintentional, and repeatable rather than accidental.
- Writing unit tests provides evidence of the ease and ease of unit testing. It helps to show the evolution of your code; Low coupling, high cohesion and other characteristics;
- Running unit tests provides evidence about the behavior of your code. It helps to indicate the runtime quality of the application;
- Use bulletin boards and cards to make progress visible and concrete. Tasks can be classified as unstarted, in progress, or completed without reference to hidden project management tools or tracking programmers’ fictitious status reports;
- Improve visibility of development schedule (or lack thereof). Can fully show the reality;
Messaging addresses concurrency
Programmers probably start learning about computers by teaching them how to deal with concurrency. Concurrency is a difficult problem, focusing on threads, semaphores, monitors, concurrent access variables, security issues, and so on.
But what’s the root of the problem? — Shared memory.
Almost all concurrency issues that people talk about are related to shared memory usage: race risks, deadlocks, live locks, and so on.
Either abandon concurrency or avoid shared memory!
It’s certainly impossible to abandon concurrency, so should we avoid shared memory?
In fact, we can use processes and messaging instead of threads and shared memory as our programming model. A process here simply means a protected independent unit with executable code, not necessarily an operating system process.
Languages such as Erlang (and Occam before it) have shown that processes are a very successful mechanism for programming concurrent and parallel systems. Such systems do not have the synchronization pressures of shared memory, multi-threaded systems. In addition, there is a formal model — communication sequential processes (CSP) — that can be applied as part of such systems engineering.
We can also go a step further and introduce a data flow system as a computing method. In a data flow system, there is no explicitly programmed flow of control. Instead, a directed graph of the operators connected by the data path is created and the data is entered into the system. Controlled by data readiness within the system, no synchronization issues.
Using messaging instead of shared memory programming is probably the most successful approach to a system that achieves the parallelism prevalent in computer hardware.
Code for your future self
We’re all smart people, but we still think that the project code we’re writing or the problem we’re solving is going to be a big problem for the people who are going to accept it. Even after a while, I can’t read what I wrote……
The authors give an example:
One of his students, Joe, was in a data structures class and he asked Joe, “I don’t know what your code is doing. You have a brother, don’t you?”
Joe said, “Yes, he’s learning to code, too!”
“I wonder if he can read this code,” the teacher asked.
Joe said, “No, it’s too hard!”
The teacher said, “This is real working code that your brother will be hired to maintain and update in a few years. What did you do for him?”
“I see,” said Joe. “I’m going to write better so Phil can understand it!”
. I have to say, it’s a little awkward to translate, but it’s true.
Make the best use of polymorphic
Polymorphism is one of the basic ideas of object orientation. The word is taken from the Greek word meaning many poly forms (morph). In programming, polymorphism refers to the multiple forms of objects or methods of a particular class.
Use code to demonstrate, such as the following to implement a simple shopping cart:
public class ShoppingCart { private ArrayList<Item> cart = new ArrayList<Item>(); public void add(Item item) { cart.add(item); } public Item takeNext() { return cart.remove(0); } public boolean isEmpty() { return cart.isEmpty(); }}Copy the code
Suppose our online store offers items to download and items to ship. Let’s build another action:
public class Shipping { public boolean ship(Item item, SurfaceAddress address) { ... } public boolean ship(Item item, EMailAddress address { ... }}Copy the code
When the customer completes the checkout, we need to ship the goods:
while (! cart.isEmpty()) { shipping.ship(cart.takeNext(), ???) ; }Copy the code
Another solution is to create two classes that both extend Item. Let’s call these downloadableItems and SurfaceItems. Promote Item as an interface that supports a single method, SHIP. To ship the contents of the shopping cart, call the item.ship(shipper).
public class DownloadableItem implements Item { public boolean ship(Shipping shipper) { shipper.ship(this, customer.getEmailAddress()); } } public class SurfaceItem implements Item { public boolean ship(Shipping shipper) { shipper.ship(this, customer.getSurfaceAddress()); }}Copy the code
In this example, we delegate the responsibility for processing to each Item. Since each item knows its best mode of transportation, this arrangement eliminates the need for if-then-else.
The code also demonstrates two patterns that are often used together: Command and Double Dispatch. The effective use of these patterns depends on the effective use of polymorphism. With them, the number of if-then-else blocks in our code will be reduced.
While in some cases it is more practical to use if-then-else than polymorphism, more often a polymorphic coding style will result in a smaller, more readable, and more stable code base.
Make friends with tests
Whether they call tests quality assurance or quality control, many programmers prefer to call them “trouble.” Programmers seem to have an adversarial relationship with testing because tests seem too picky or they want everything to be perfect……
You may think your testers are writing long reports to make you feel bad about your code, but it will make your users give you better feedback
In fact, testing helps us solve problems, and good testing is the strongest guarantee of code quality on the line.
It’s better to be suspected by the test than by the user.
It may be hard to accept that the testers who constantly expose every little bug in your code are actually your friends. (This melon tries to accept ~)
Environmental synchronization
The author has seen several projects in which builds rewrite parts of the code to generate custom binaries for each target environment.
But this always makes things more complicated than they should be and puts the team at risk of having different versions installed.
The authors suggest building a binary that you can identify and promote at all stages in the release pipeline, separate from the project code.
Keep environment information versioned! There’s nothing worse than destroying an environmental configuration and not being able to figure out what’s going on.
Environment information should be versioned separately from code because it can change at different rates and for different reasons.
Some teams use distributed version control systems for this, such as Bazaar and Git, because they make it easier to push changes made in the production environment (which inevitably occur) back to the repository.
OK, the above is the series of the third share (a total of 5), pay attention to the column, the series of continuous tracking ~
I’m Anthony Digger, output exposed input, technology insight life, see you next time