02 Detailed Analysis and Abstract Design of Specific Business Requirements

02 Detailed Analysis and Abstract Design of Specific Business Requirements #

After the previous requirements analysis, the business requirements of the parking fee business in the shopping mall are already very clear. In this section, based on the output of the previous text, we will start the system design work, including functional module design, storage design, architecture design, etc., to provide a good foundation for later coding.

Some students may have doubts. If we are using Agile, why do we still need to design? Can’t we just start coding directly? Agile advocates responding to changes and reducing documentation. Many friends have misunderstandings and think that Agile does not require design or documentation, but is all about speed. Anything that hinders implementation and delivery should be eliminated. In fact, Agile does not eliminate documents and design. Critical documents, images, and designs still need to be retained, such as storage design, key business process design, etc. However, they are not limited to document forms. They can be sketches on whiteboards or A4 papers, sticky notes, or formal documents. It is only necessary to express the meaning and facilitate subsequent retracing.

Data Entity Relationships #

Based on the above business situation, it is divided into seven small modules according to the domain, and corresponding entities and events are divided in each module. A simplified diagram of the key data entity-relationship diagram (not including all entities) is shown below:

  1. Member, Vehicle, Monthly Pass (binding phone number, inputting vehicle information, issuing monthly pass)
  2. Parking Space, Gate (vehicle parking, vehicle leaving)
  3. Points (check-in, redemption)
  4. Charging Rules (entry, exit)
  5. Transaction Records (payment, recharge)
  6. Messages (push)
  7. Car Wash

img

Business Module Design #

According to the situation identified in the first requirements analysis, we have identified the key processes, main business modules, and main business entities in the modules. This case can be developed using a single entity pattern, but in order to simulate the scenario of microservice development, we will follow the design approach of microservices.

Based on the key business entity relationships and events, the business modules are integrated into seven sub-services:

  • Member service, including member information, vehicle information, and member monthly pass
  • Basic resource service, including parking space, gate, and vehicle parking records
  • Charging service, vehicle entry and exit records, and charging rules
  • Points service, points redemption, member points, and member check-in points
  • Finance service, payment records, recharge records, financial statistics
  • Message service, recording notification content
  • Car wash service, using car wash vouchers obtained from point redemption to wash cars inside the park

There is no unified standard in the industry for the granularity of service decomposition. It must be divided based on the company’s team situation, personnel capabilities, and product usage. It should not be too detailed, and too coarse will also lose the meaning of microservices. Each microservice can be maintained by two to three developers to avoid excessive maintenance and scattered energy, while ensuring a quick response to maintenance and upgrades.

Storage Design #

One advantage of the microservice architecture style is encapsulation with persistence. We can choose different persistence technologies according to the needs of each service. Choose the method of data storage based on the characteristics of each data type, which is the mixed persistence, combining structured storage with unstructured storage. Different storage models are used between different services, and mixed storage can also be used within a single service. Since a microservice structure is to be used, the development, operation, deployment, and maintenance are all separate small applications. The internal business logic processing, database access, and databases of each small application are independent.

Based on the business scenario of this case, we split it into seven sub-repositories:

  • park_member - Member Service Repository
  • park_resource - Parking Resource Service Repository
  • park_charging - Charging Service Repository
  • park_card - Points Service Repository
  • park_finance - Finance Service Repository
  • park_message - Message Service Repository
  • park-carwash - Car Wash Service Repository

In practice, some teams implementing microservices split the services but still use the same storage repository, and there should be quite a few of them in reality. It can’t be said that it’s wrong, but it just doesn’t conform to the recommendations of microservices.

Structured storage uses the community edition of MySQL 5.7+ version, and unstructured storage mainly involves caching, which uses Redis 4.0+ version. In structured storage, it is recommended to design some common fields, mainly for tracking data records. The common fields of the library table structure are as follows:

`create_by` varchar(32) DEFAULT NULL COMMENT 'Creator',
`create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Date',
`update_by` varchar(32) DEFAULT NULL COMMENT 'Updater',
`update_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Update Date',
`remark` varchar(500) DEFAULT NULL COMMENT 'Remarks',
`version` int(4) DEFAULT '0' COMMENT 'Version',
`state` int(4) DEFAULT '1' COMMENT 'State'

The creator, creation time of each data record, and subsequent updater, update time, non-business-related remarks, version, and state are helpful for data maintenance personnel to identify. It is recommended to add them to each table.

The script for creating the databases is as follows:

CREATE DATABASE `park_member` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_resource` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_charging` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_card` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_finance` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_message` CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `park_carwash` CHARACTER SET utf8 COLLATE utf8_general_ci;

park_member Database Table Initialization #

-- ----------------------------
-- Table structure for member
-- ----------------------------
DROP TABLE IF EXISTS `member`;
CREATE TABLE `member` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `phone` varchar(11) DEFAULT NULL COMMENT 'Phone Number',
  `birth` varchar(10) DEFAULT NULL COMMENT 'Date of Birth',
  `full_name` varchar(20) DEFAULT NULL COMMENT 'Full Name',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Member Information';

-- ----------------------------
-- Table structure for month_card
-- ----------------------------
DROP TABLE IF EXISTS `month_card`;
CREATE TABLE `month_card` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `card_no` varchar(20) DEFAULT NULL COMMENT 'Membership Card Number',
  `start` varchar(16) DEFAULT NULL COMMENT 'Validity Period Start',
  `ends` varchar(16) DEFAULT NULL COMMENT 'Validity Period End',
  `member_id` varchar(32) DEFAULT NULL COMMENT 'Member ID',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Member Monthly Card Information';

-- ----------------------------
-- Table structure for vehicle
-- ----------------------------
DROP TABLE IF EXISTS `vehicle`;
CREATE TABLE `vehicle` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `member_id` varchar(32) DEFAULT NULL COMMENT 'Member ID',
  `plate_no` varchar(10) DEFAULT NULL COMMENT 'License Plate Number',
  `vehicle_inf` varchar(50) DEFAULT NULL COMMENT 'Vehicle Model',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Member Vehicle';



#### Initialization Table Structures for park_resource Database


-- ----------------------------
-- Table structure for brake
-- ----------------------------
DROP TABLE IF EXISTS `brake`;
CREATE TABLE `brake` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `code` varchar(20) DEFAULT NULL COMMENT 'Code',
  `desc` varchar(50) DEFAULT NULL COMMENT 'Description',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Parking Lot Barrier';

-- ----------------------------
-- Table structure for stall
-- ----------------------------
DROP TABLE IF EXISTS `stall`;
CREATE TABLE `stall` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `code` varchar(10) DEFAULT NULL COMMENT 'Code',
  `is_parked` int(2) DEFAULT NULL COMMENT 'Is Occupied',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Parking Space Table';

-- ----------------------------
-- Table structure for stall_parked
-- ----------------------------
DROP TABLE IF EXISTS `stall_parked`;
CREATE TABLE `stall_parked` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `stall_id` varchar(32) DEFAULT NULL COMMENT 'Stall ID',
  `plate_no` varchar(30) DEFAULT NULL COMMENT 'License Plate',
  `mtype` int(2) DEFAULT NULL COMMENT '0 for Entry, 1 for Exit',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Parking Space Docking Record';



#### Initialization Table Structures for park_charging Database


-- ----------------------------
-- Table structure for charging_rule
-- ----------------------------
DROP TABLE IF EXISTS `charging_rule`;
CREATE TABLE `charging_rule` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `start` int(4) DEFAULT NULL COMMENT 'Parking Time Start',
  `end` int(4) DEFAULT NULL COMMENT 'Parking Time End',
  `fee` float DEFAULT NULL COMMENT 'Charge',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Charging Rules';

-- ----------------------------
-- Table structure for entrance
-- ----------------------------
DROP TABLE IF EXISTS `entrance`;
CREATE TABLE `entrance` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`plate_no` varchar(10) DEFAULT NULL COMMENT '车牌',
`brake_id` varchar(32) DEFAULT NULL COMMENT '闸机号',
PRIMARY KEY (`id`) USING BTREE,
KEY `no_idx` (`plate_no`),
KEY `member_idx` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='车辆入场';

-- Table structure for vexists
DROP TABLE IF EXISTS `vexists`;
CREATE TABLE `vexists` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`brake_id` varchar(32) DEFAULT NULL COMMENT '闸机号',
`plate_no` varchar(32) DEFAULT NULL COMMENT '车牌号',
PRIMARY KEY (`id`) USING BTREE,
KEY `no_idx` (`plate_no`),
KEY `member_idx` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='车辆驶出';

#### park_card Table Initialization Structure

-- Table structure for exchange
DROP TABLE IF EXISTS `exchange`;
CREATE TABLE `exchange` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`card_qty` int(11) DEFAULT NULL COMMENT '积分数量',
`ctype` int(4) DEFAULT NULL COMMENT '0 优惠券,1 洗车券',
`code` varchar(30) DEFAULT NULL COMMENT '券编码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='积分兑换';

-- Table structure for member_card
DROP TABLE IF EXISTS `member_card`;
CREATE TABLE `member_card` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`cur_qty` varchar(20) DEFAULT NULL COMMENT '当前可用积分',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员积分';

-- Table structure for member_sign
DROP TABLE IF EXISTS `member_sign`;
CREATE TABLE `member_sign` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`cnt` int(4) DEFAULT NULL COMMENT '积分数量',
`ctype` int(4) DEFAULT NULL COMMENT '0 签到,1 商场消费',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员签到';

#### park_finance Table Initialization Structure

-- Table structure for billing
DROP TABLE IF EXISTS `billing`;
CREATE TABLE `billing` (
`id` varchar(32) NOT NULL DEFAULT '',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`fee` float DEFAULT '0' COMMENT '支付金额',
`plate_no` varchar(10) DEFAULT NULL COMMENT '车牌号',
`duration` float DEFAULT '0' COMMENT '停车时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `no_idx` (`plate_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='车辆驶出支付流水';

-- Table structure for month_card_recharge
DROP TABLE IF EXISTS `month_card_recharge`;
CREATE TABLE `month_card_recharge` (
`id` varchar(32) NOT NULL DEFAULT '',
`card_no` varchar(20) DEFAULT NULL COMMENT '月卡号',
`member_id` varchar(32) DEFAULT NULL COMMENT '会员编号',
`amount` float DEFAULT NULL COMMENT '充值金额',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='会员月卡充值';

park_message Library Initialization Table Structure #

-- ----------------------------
-- Table structure for message
-- ----------------------------
DROP TABLE IF EXISTS `message`;
CREATE TABLE `message` (
  `id` varchar(32) NOT NULL DEFAULT '',
  `mtype` char(10) DEFAULT NULL COMMENT 'Message type, PAY: payment message, BIND: binding information',
  `mcontent` varchar(500) DEFAULT NULL COMMENT 'Message content',
  `member_id` varchar(32) DEFAULT NULL COMMENT 'Member',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Push message';

park_carwash Database Table Structure #

-- ----------------------------
-- Table structure for car_wash
-- ----------------------------
DROP TABLE IF EXISTS `car_wash`;
CREATE TABLE `car_wash` (
  `id` varchar(32) NOT NULL,
  `member_id` varchar(32) DEFAULT NULL COMMENT 'Member ID',
  `plate_no` varchar(10) DEFAULT NULL COMMENT 'License Plate Number',
  `ticket_code` varchar(20) DEFAULT NULL COMMENT 'Car wash voucher code',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Complete table structure script address, click the link below:

https://github.com/backkoms/spring-cloud-alibaba-ParkingLot/tree/master/src/script

Initializing Data #

With the preliminary database model, it is necessary to initialize some data, such as billing rules, gate information, and parking space information.

Gate Data #

INSERT INTO `brake` VALUES ('4edb0820241041e5a0f08d01992de4c0', 'ct1', 'Entry Gate', 'admin', '2019-12-27 11:37:22', NULL, '2019-12-27 11:37:22', NULL, 0, 1);
INSERT INTO `brake` VALUES ('989170c529a348b3b93bf2a4653e8ea9', 'ct2', 'Entry Gate', 'admin', '2019-12-27 11:37:45', NULL, '2019-12-27 11:37:45', NULL, 0, 1);
INSERT INTO `brake` VALUES ('e489029055654bccb3cd601f0be71c41', 'ct3', 'Exit Gate', 'admin', '2019-12-27 11:37:36', NULL, '2019-12-27 11:37:36', NULL, 0, 1);
INSERT INTO `brake` VALUES ('f726873ed17441ea8dfbf78381bcde78', 'ct4', 'Exit Gate', 'admin', '2019-12-27 11:37:41', NULL, '2019-12-27 11:37:41', NULL, 0, 1);

Parking Space Data #

INSERT INTO `stall` VALUES ('004ac347b94e42bb8f0f6febd3265e35', 'P336', 0, 'admin', '2019-12-27 11:42:03', NULL, '2019-12-27 11:42:03', NULL, 0, 1);
INSERT INTO `stall` VALUES ('008773e089664ce49607c86b89dd8c0f', 'P250', 0, 'admin', '2019-12-27 11:42:03', NULL, '2019-12-27 11:42:03', NULL, 0, 1);
INSERT INTO `stall` VALUES ('0110ef02554f46ce91a3eeec6ecf2f95', 'P224', 0, 'admin', '2019-12-27 11:42:03', NULL, '2019-12-27 11:42:03', NULL, 0, 1);
INSERT INTO `stall` VALUES ('014f1f2b972e4e0092d749a7437f824d', 'P577', 0, 'admin', '2019-12-27 11:42:04', NULL, '2019-12-27 11:42:04', NULL, 0, 1);
INSERT INTO `stall` VALUES ('019f4aa0c22849e1a5758aaa33b855df', 'P229', 0, 'admin', '2019-12-27 11:42:03', NULL, '2019-12-27 11:42:03', NULL, 0, 1);

Billing Rules #

INSERT INTO `charging_rule` VALUES ('41ed927623cf4a0bb5354b10100da992', 0, 30, 0, 'admin', '2019-12-27 11:26:08', NULL, '2019-12-27 11:26:08', 'Free within 30 minutes', 0, 1);
INSERT INTO `charging_rule` VALUES ('41ed927623cf4a0bb5354b10100da993', 31, 120, 5, 'admin', '2019-12-27 11:26:12', NULL, '2019-12-27 11:26:12', 'Within 2 hours, 5 yuan', 0, 1);
INSERT INTO `charging_rule` VALUES ('4edb0820241041e5a0f08d01992de4c0', 121, 720, 10, 'admin', '2019-12-27 11:34:06', NULL, '2019-12-27 11:34:06', 'Over 2 hours but less than 12 hours, 10 yuan', 0, 1);
INSERT INTO `charging_rule` VALUES ('7616fb412e824dcda41ed9367feadfda', 721, 1440, 20, 'admin', '2019-12-27 13:35:37', NULL, '2019-12-27 13:35:37', 'From 12 to 24 hours, 20 yuan', 0, 1);

Unstructured Storage #

Redis middleware is mainly used to store real-time information about available parking spaces, billing rules, and other hot data.

Architectural Design #

There is no perfect architecture, only the most suitable architecture. All system design principles should ultimately aim to solve business problems and continuously iterate and evolve with the development of the business. After dividing the business modules and storage models mentioned above, the basic code architecture is already clear. Combining business modules and the characteristics of microservice architecture, the functional architecture design diagram is produced.

img

Based on the overall functional architecture diagram, specific functional components can be used to implement the corresponding functions. As mentioned earlier, the Spring Cloud stack includes many ready-to-use components, which provides great convenience for rapid development of microservices. At the same time, incorporating some commonly used efficient tools to improve coding efficiency, such as Lombok and MBG.

img

Thought-provoking Question #

The Lombok component has been mentioned as a component library that is helpful in simplifying code development. Do you have any useful component libraries that can efficiently function in project development?