⬆️ ⬇️

The book "Clean Architecture. The art of software development

image “Perfect Programmer” and “Clean Code” - Robert Martin's legendary bestsellers - tell you how to achieve the heights of professionalism. “Pure architecture” continues this theme, but does not offer several options in the “solve it yourself” style, but explains what exactly should be done, for what reason, and why exactly such a decision will become crucial for your success.



Robert Martin gives direct and concise answers to key questions of architecture and design. "Pure architecture" must be read by developers of all levels, system analysts, architects and every programmer who wants to climb the career ladder or at least influence the people who are engaged in this work. All architectures follow the same rules! Robert Martin (Uncle Bob)



Proficiency Test



Why are so many software turning into firmware? It seems that the main reason is the desire to get a valid embedded code and almost no attention is paid to its structuring to increase the service life. Kent Beck describes three steps in creating software (the words of Kent are quoted in quotes and my comments are in italics):



  1. "First make it work." You will remain out of work if it does not work.
  2. "Then rewrite it correctly." Reorganize the code so that you and others can understand and develop it when you need to change or understand something.
  3. "Then make it work fast." Reorganize the code to achieve the "necessary" performance.


Most of the embedded systems that I had to see seemed to be written with a single thought in my head: “Make it work,” and sometimes with an obsessive idea: “Make it work fast,” embodied by introducing micro-optimizations at every opportunity. In his book The Mythical Man-Month, Fred Brooks proposes "to plan on giving up the first version." Kent and Fred advise almost the same thing: find out how it works and find the best solution.

')

Embedded software is no different with respect to these problems. Many non-embeddable applications are brought only to the “working” stage, and little is done to make the code correct and serve for a long time.



Getting a working application is what I call a proficiency test for a programmer. A programmer who develops software, whether embedded or not, who only cares about getting a working application, harms his products and his employer. Programming is more than the ability to write working applications.



As an example, take a look at the following functions that are in the same file of a small embedded system, written in the course of passing a proficiency test:



ISR(TIMER1_vect) { ... } ISR(INT2_vect) { ... } void btn_Handler(void) { ... } float calc_RPM(void) { ... } static char Read_RawData(void) { ... } void Do_Average(void) { ... } void Get_Next_Measurement(void) { ... } void Zero_Sensor_1(void) { ... } void Zero_Sensor_2(void) { ... } void Dev_Control(char Activation) { ... } char Load_FLASH_Setup(void) { ... } void Save_FLASH_Setup(void) { ... } void Store_DataSet(void) { ... } float bytes2float(char bytes[4]) { ... } void Recall_DataSet(void) { ... } void Sensor_init(void) { ... } void uC_Sleep(void) { ... } 


In this order, the functions were declared in the source file. And now we divide them and group them by the tasks to be solved:



functions that implement the subject logic:



• float calc_RPM (void) {...}

• void Do_Average (void) {...}

• void Get_Next_Measurement (void) {...}

• void Zero_Sensor_1 (void) {...}

• void Zero_Sensor_2 (void) {...}



functions serving the hardware platform:



• ISR (TIMER1_vect) {...} *

• ISR (INT2_vect) {...}

• void uC_Sleep (void) {...}



functions that respond to button presses:



• void btn_Handler (void) {...}

• void Dev_Control (char Activation) {...}



function that reads data from an analog-to-digital hardware converter:



• static char Read_RawData (void) {...}



functions writing values ​​to long-term storage:



• char Load_FLASH_Setup (void) {...}

• void Save_FLASH_Setup (void) {...}

• void Store_DataSet (void) {...}

• float bytes2float (char bytes [4]) {...}

• void Recall_DataSet (void) {...}



a function that does not do what its name implies:



• void Sensor_init (void) {...}



Looking into the other files of this application, I found many obstacles hindering the understanding of the code. I also found that organizing files implies the only way to test this code directly inside the target device. Virtually every bit of this code knows what is related to a specialized microprocessor architecture using the “extended” C1 language constructs that tie the code to a specific set of tools and the microprocessor. This code does not have the slightest chance to serve for a long time if it is decided to transfer the product to another hardware platform.



The application works: the engineer passed the test for professional suitability. But it cannot be said that it has a clean embedded architecture.



Binding to equipment - a bottleneck



There are a lot of special problems faced by developers of embedded systems and not familiar to the developers of conventional software. For example, limited memory, time constraints on operations, limited I / O capabilities, unconventional user interfaces, and the presence of sensors and contacts connecting to the outside world. In most cases, hardware develops in parallel with software and firmware. As an engineer who develops code for this type of system, you may not have a place to run the code. But this is not the worst - the resulting equipment may have its own drawbacks, which slows down the development of software more than usual.



Yes, embedded software has its own characteristics, and embedded system engineers are special people. But the development of embedded systems is not so special that the principles described in this book cannot be applied to embedded systems.



One of the special problems of embedded systems is the close dependency on hardware. When embedded code is structured without applying the principles and techniques of a clean architecture, one often comes across a scenario where the code can be tested only on target hardware. If this equipment is the only place where testing is possible, such a close relationship begins to slow you down.



Net Embedded Architecture - Testing Supporting Architecture



Let's take a look at how some architectural principles apply to embedded software and firmware, and how they can help get rid of tight hardware bindings.



Levels



The division into levels can be done in different ways. Let's begin with the three-level organization shown in Fig. 29.1. Below is the level of equipment. As Doug warns, due to improved technology and according to Moore's law, equipment will change. Some components become obsolete, and they are replaced by new components that consume less electricity, or have better performance, or are cheaper. Regardless of the reasons, I, as an embedded systems engineer, would not like to do more than is necessary when the inevitable change in equipment finally occurs.



image


The separation between the equipment and the rest of the system is an objective reality, at least after the equipment has been defined (fig. 29.2). This is where problems often arise when trying to pass a proficiency test. Nothing prevents hardware knowledge from infecting the entire code. If you do not take care when structuring the code and do not limit the leakage of information about one module to another, the code will be difficult to change. I speak not only about the case when the equipment changes, but also about the situation when you need to correct the error or make a change at the user's request.



image


Mixing software and firmware is an anti-pattern. Code demonstrating this anti-pattern will resist changes. In addition, changes are fraught with hazards, often leading to unintended consequences. Even minor changes require complete regression testing of the system. If you have not created tests with external equipment, prepare to do manual testing and then wait for new error messages.



Equipment is a detail



The line between software and firmware is usually not as clearly visible as the line separating code and hardware (Fig. 29.3).



One of the tasks of the developer of embedded software is to strengthen this line. The boundary between software and firmware (Figure 29.4) is called the Hardware Abstraction Layer (HAL). This is not a new idea: it was implemented in personal computers in the pre-Windows era.



image


image


The HAL layer exists for the software above it, and its API must adapt to the needs of this software. For example, the firmware can store bytes and arrays of bytes in flash memory, and the application needs to store and read name / value pairs using some kind of storage mechanism. Software should not care about the details of storing name / value pairs in flash memory, on a rotating disk, in the cloud or in main memory. The hardware abstraction layer (HAL) provides a service and does not disclose to the software how it works. Flash support implementation is a part that should be hidden from software.



Another example: LED control is tied to a GPIO bit. The firmware can provide access to the GPIO bits, and the HAL layer can have the Led_TurnOn (5) function. This is a fairly low-level layer of hardware abstraction. Let's see how to raise the level of abstraction in terms of software / product. What information does the LED report? Suppose that the inclusion of the LED indicates a low battery. At some level, the firmware (or platform support package) may provide the Led_TurnOn (5) function, and the HAL layer may provide the Indicate_LowBattery () function. In this way, the HAL layer expresses the purpose of the service for the application. In addition, levels may contain sublevels. This is more like a repeating fractal pattern than a limited set of predefined levels. The purpose of the GPIO I / O is the details that should be hidden from the software.



»More information about the book can be found on the publisher's website.

» Table of Contents

» Excerpt



For Habrozhiteley a discount of 20% on the coupon - Pure architecture

Source: https://habr.com/ru/post/353170/



All Articles