Skip to content

Commit 4890000

Browse files
Update README.md
1 parent 52efbdd commit 4890000

File tree

1 file changed

+219
-2
lines changed

1 file changed

+219
-2
lines changed

README.md

Lines changed: 219 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,219 @@
1-
# reverse-design
2-
reverse-design.coders.info - Reverse design is focusing on logs and step by steps to unit test and code
1+
# [reverse-design](http://reverse-design.coders.info)
2+
3+
4+
## What mean reverse design in software development?
5+
6+
Reverse design, also commonly referred to as **reverse engineering** in software development
7+
8+
Reverse design is focusing on logs and step by steps to unit test and code
9+
10+
How to call the design software focusing on creating logs file, integration test, unit tests, and on the end on writing the code?
11+
12+
13+
## Reverse modular design
14+
15+
Reverse modular design principles working based on such main principles:
16+
+ TDD
17+
+ Reverse Engineering
18+
+ Modular design to create monorepo
19+
20+
21+
Reverse design is from logs manual written to descibe the expected and unexpected behaviors, and next the the mock function with expected inputs and outputs, writing test and on the end writing the code inside the mocks.
22+
23+
1. Create 2 logs file: info.log, error.log
24+
2. Describe line by line with values, the outputs. So we should know how should work the software when should be seeing an error
25+
3. Write the logs function or the decorator to build the logs on each starting the function in form of sentence
26+
4. Write the mock function with just name, parameters and example value on return
27+
5. Write integration, functional and unit test
28+
6. Test each test with live data from function, and replace step by step the empty mocks to source code
29+
30+
31+
32+
## reverse Engineering
33+
34+
is the process of analyzing a system to identify the system's components and their interrelationships and to create representations of the system in another form or at a higher level of abstraction.
35+
36+
Reverse engineering is a sensitive and often controversial technique because, in some cases, it can be used to copy or recreate someone else's work without the original creator's permission. Consequently, there are legal and ethical implications to consider, especially in relation to copyright, patents, and trade secrets. Developers must ensure that they are not violating intellectual property laws when engaging in reverse design or reverse engineering.
37+
38+
### How to build an software based on reverse desgin principles?
39+
40+
This is often done with the following purposes:
41+
42+
#### Context Understandin
43+
To gain a better understanding of how a particular piece of software works, especially if the original source code is not available. This is common when working with legacy systems where the original designers are no longer available and documentation is lacking.
44+
45+
#### Debugging
46+
To identify the source of a problem within a piece of software for which the source code may be difficult to read or understand, often because of poor documentation or complex interactions within the system.
47+
48+
49+
## Why it's necessary?
50+
51+
#### Interoperability
52+
To enable a product to interoperate with another product that is designed to be incompatible. An example could be writing a new piece of software to interoperate with a legacy system without changing it.
53+
54+
#### Security Analysis
55+
To assess the security of a system by searching for vulnerabilities that can be used to attack the system.
56+
57+
#### Product Migration or Integration
58+
To facilitate the transfer of the product from one hardware or software environment to another, or to integrate with another product with compatible functionalities.
59+
60+
#### Code Recovery
61+
To recover lost source code or to convert code written in an obsolete or discontinued language to a modern language.
62+
63+
#### Documentation
64+
To create or enhance documentation for legacy systems where documentation may be incomplete or outdated.
65+
66+
#### Innovation
67+
To learn from existing solutions to build new, improved systems that do things differently or more efficiently.
68+
69+
70+
71+
## How to write the code with modular reverse design principle?
72+
73+
Implement a basic logging system in Python, using the built-in logging module.
74+
Below I will outline each step to create this logging system and demonstrate usage with a mock function and tests:
75+
76+
77+
### Create 2 logs file: `info.log`, `error.log`
78+
79+
```python
80+
import logging
81+
82+
# Configure logger
83+
logging.basicConfig(level=logging.INFO)
84+
logger = logging.getLogger()
85+
86+
# Create handlers for info and error
87+
info_handler = logging.FileHandler('info.log')
88+
info_handler.setLevel(logging.INFO)
89+
90+
error_handler = logging.FileHandler('error.log')
91+
error_handler.setLevel(logging.ERROR)
92+
93+
# Create formatter and add it to handlers
94+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
95+
info_handler.setFormatter(formatter)
96+
error_handler.setFormatter(formatter)
97+
98+
# Add handlers to the logger
99+
logger.addHandler(info_handler)
100+
logger.addHandler(error_handler)
101+
```
102+
103+
### Describe line by line with values, the outputs
104+
105+
Assuming the above logger is in place, let's create a scenario:
106+
107+
```python
108+
def risky_division(x, y):
109+
try:
110+
result = x / y
111+
logger.info(f"Successful division: {x} / {y} = {result}")
112+
return result
113+
except ZeroDivisionError as e:
114+
logger.error(f"Error dividing {x} by zero: {str(e)}")
115+
return None
116+
117+
# Expected output in `info.log` after risky_division(10, 2) is called:
118+
# 2023-03-17 10:00:00,000 - root - INFO - Successful division: 10 / 2 = 5.0
119+
120+
# Expected output in `error.log` after risky_division(10, 0) is called:
121+
# 2023-03-17 10:01:00,000 - root - ERROR - Error dividing 10 by zero: division by zero
122+
```
123+
124+
### Write the logs function or the decorator to build the logs on each starting the function in form of a sentence
125+
126+
```python
127+
def log_function_call(func):
128+
def wrapper(*args, **kwargs):
129+
logger.info(f"Function {func.__name__} called with arguments: {args} and keyword arguments: {kwargs}")
130+
return func(*args, **kwargs)
131+
return wrapper
132+
```
133+
134+
### Write the mock function
135+
with just name, parameters, and example value on return
136+
137+
```python
138+
@log_function_call
139+
def mock_function(x, y):
140+
# Placeholder for a complex operation
141+
return {"result": "example_value"}
142+
143+
# Example invocation:
144+
mock_function(5, 3) # This should log an info message about the function being called
145+
```
146+
147+
### Write integration, functional, and unit tests
148+
Using Python's unittest framework, we'd write tests as follows:
149+
```python
150+
import unittest
151+
152+
class TestLoggingFunctionality(unittest.TestCase):
153+
def test_risky_division_success(self):
154+
self.assertEqual(risky_division(10, 2), 5.0) # Unit test
155+
156+
def test_risky_division_failure(self):
157+
self.assertIsNone(risky_division(10, 0)) # Unit test
158+
159+
def test_mock_function(self):
160+
self.assertEqual(mock_function(5, 3), {"result": "example_value"}) # Integration/functional test
161+
162+
# Run the tests
163+
if __name__ == '__main__':
164+
unittest.main()
165+
```
166+
167+
### Test function
168+
169+
Test each function with live data from function, and replace step by step the empty mocks to source code
170+
Initially, one would run the tests with the implementation of `risky_division` and `mock_function` in place.
171+
Once the tests pass as expected with mock implementations, you can gradually replace the mock functionality with the actual business logic you intend to implement and re-run the tests until all pass, ensuring that your code changes do not break existing functionality. This process is iterative and aligns with Test-Driven Development (TDD) practices.
172+
173+
174+
Verifying the content of log files as a part of tests would involve reading the log files and checking that the appropriate entries have been made.
175+
This can be done using Python's built-in `unittest` framework.
176+
177+
Here's how you can extend the previously defined `TestLoggingFunctionality` class to include test cases for file contents:
178+
179+
```python
180+
import unittest
181+
import os
182+
183+
class TestLoggingFunctionality(unittest.TestCase):
184+
185+
@staticmethod
186+
def read_last_line(logfile):
187+
with open(logfile, "rb") as f:
188+
f.seek(-2, os.SEEK_END)
189+
while f.read(1) != b"\n":
190+
f.seek(-2, os.SEEK_CUR)
191+
last_line = f.readline().decode()
192+
return last_line
193+
194+
def test_risky_division_success_log_entry(self):
195+
risky_division(10, 2)
196+
last_line = self.read_last_line('info.log')
197+
self.assertIn("Successful division: 10 / 2 = 5.0", last_line)
198+
199+
def test_risky_division_failure_log_entry(self):
200+
risky_division(10, 0)
201+
last_line = self.read_last_line('error.log')
202+
self.assertIn("Error dividing 10 by zero", last_line)
203+
204+
# Other tests can go here...
205+
206+
# Run the tests
207+
if __name__ == '__main__':
208+
unittest.main()
209+
```
210+
211+
Note that `read_last_line` is a utility method that reads the last line from a specified log file assuming it's where the latest log entry would be.
212+
This method opens the file, seeks to the end, and reads backwards until it finds a new line. It then reads and returns the last line of the file.
213+
214+
For a more comprehensive testing process, you would want to clear the log file content before each test or use a dedicated log file for each test to ensure you are only checking the latest entries. Additionally, handling potential file I/O errors would be important in a production-grade testing suite.
215+
216+
Remember to reset the log file's state after each test or use unique log file names for each test run to avoid one test's log entries affecting another's assertions.
217+
218+
Keep in mind that this testing method is quite fragile, especially for larger-scale applications, since it relies on the assumption that the last log entry corresponds to the latest action—which might not be the case in multi-threaded or heavily-logged applications. In such cases, specialized tools or more sophisticated logging handling may be required to ensure accurate tests.
219+

0 commit comments

Comments
 (0)