├── Linux programming ├── Linux.md ├── README.md ├── deep-understanding.md ├── io_example.cpp ├── key-point.md ├── main.cpp └── redirect-and-pipe.md ├── README.md ├── Software-Architecture ├── 1. general.md ├── 10. design-problem.md ├── 2. quality_attribute.md ├── 3.architecture-pattern and QA.md ├── 3.architecture-pattern.md ├── 4. add_design.md ├── 5. design_pattern.md ├── 6. documenting.md ├── 7. evaluation.md ├── 8 . 软件产品线(课本描述).md ├── 8. product-line.md ├── 8. (1) product-line.md ├── 9. mirco_service.md └── README.md ├── machine-learning ├── N2N.md ├── network-compression.md └── semi-vae.md └── resource └── img.jpg /Linux programming/Linux.md: -------------------------------------------------------------------------------- 1 | ## Linux 复习 2 | 3 | ### 一. 零碎知识点 4 | 5 | 1. **Linux 创始人**: Linus torvalds 6 | 7 | 2. **Linux 发行版**: Redhat, Debian, Suse, Mandrake, ubuntu 8 | 9 | 3. **虚拟终端**: Linux 中控制台模拟了很多终端,每个虚拟终端可以被看作成一个独立的,直接相连的控制台。 不同的用户可以使用不同的虚拟终端。 一般情况下 1-6 是命令行终端, 7是图形界面终端。 10 | 11 | 4. 源代码如何编译成可执行码 12 | 13 | 暂时链接到第12条 14 | 15 | 5. **进程的概念**: 16 | 17 | 进程是一个正在执行的程序实例。由程序体,当前值(?),状态信息,以及操作系统用于管理此进程执行情况的资源组成 18 | 19 | 6. **层次图要掌握** 20 | 21 | 直接放图 22 | 23 | 7. **重定向非常理解**: 24 | 25 | - 标准输入、标准输出、标准错误 26 | - 文件描述符:0,1,2 27 | - C库(stdio.h)的流指针:stdin,stdout,stderr 28 | - 命令行操作符 29 | - \>:将程序的输出重定向到一个文件设备文件,覆盖原来的文件 30 | - \>!:同上,但是强制覆盖 31 | - \>>:同上,但是不覆盖而是在末尾追加 32 | - <:将程序的输入重定向为某个程序 33 | 34 | 8. **管道非常理解**: 35 | 36 | |:将一个进程的标准输出作为另一个进程的标准输入 37 | 38 | 9. **shell 是怎样的进程,额外的名字** 39 | 40 | shell 是用户和操系统之间的接口,是一个核外运行的进程,具体看层次图(第6条) 41 | 42 | 各种不同的shell : ash, ash,static, bsh, bash, sh, csh, tcsh, ksh 等 43 | 44 | 10. **shell 的双重角色,工作步骤** 45 | 46 | 1. 命令解释程序 47 | * Linux的开机启动过程; 进程树 48 | * Shell的工作步骤 49 | * 打印提示符;得到命令行;解析命令;查找文件 ;准备参 50 | 数;执行命令 51 | 2. 独立的程序设计语言解释器 52 | 53 | * KISS (Keep It Small and Stupid) 54 | * Reusable tools 55 | * Redirection and pipe 56 | 57 | 11. **脚本执行的各种方式区别**: 58 | 59 | * `sh/bash/csh/some_bash script_file` 60 | 61 | * `chmod +x script_file` 62 | 63 | ​ `./scirpt_file` 64 | 65 | * `source script_file`或`. script_file` 66 | 67 | 12. **编译的原理链接和流程**,**静态库和动态库** 68 | 69 | 源文件(.c/.cpp)--预处理-->纯C代码--编译(cc)-->汇编程序(.s)--汇编(as)-->目标文件(.o)--链接(ld)-->可执行文件 70 | 71 | 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。编译之后程序文件大,但加载快,隔离性也好。 72 | 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可。 73 | 74 | 13. **Gcc g++ 常见参数。11 个参数要求掌握。 .a .o .so 要掌握** 75 | 76 | 用于编译、连接 77 | 78 | - -E:只进行预处理 79 | - -S:只进行预处理、编译 80 | - -c:预处理、编译、汇编 81 | - -o [output_file]:指定输出文件名 82 | - -g:产生符号文件(可用于调试工具) 83 | - -On:优化等价,n可以取0,1,2,3 84 | - -Wall:显示所有警告信息 85 | - -Idir:指定额外的头文件搜索路径 86 | - -Ldir:指定额外的库文件搜索路径 87 | - -lname:指定链接时搜索的库文件(name要去掉lib,如要链接pthread,pthread的静态库名为libpthread.a,则参数写成-lpthread) 88 | - -DMACROT[=DEFN]:定义宏 89 | 90 | 14. **硬连接和软连接** 91 | 92 | 软连接(符号链接)和硬连接 93 | 94 | - 软连接 95 | - 是确确实实存在的一个文件,有自己的inode号 96 | - 文件中存放被链接的文件的路径 97 | - 可以跨越文件系统 98 | - 对应系统调用symlink 99 | - 硬链接 100 | - 与被链接的文件共享同一个inode,dentry不同 101 | - 不能跨越文件系统 102 | - 对应系统调用link 103 | 104 | 15. **Makefile 文件的执行** 105 | 106 | make & makefile 107 | 108 | * makefile描述模块间的依赖关系; 109 | * make命令根据makefile对程序进行管理和维 110 | 护;make判断被维护文件的时序关系 111 | 112 | 16. **系统调用和库函数差别要掌握** 113 | 114 | - 都以C函数的形式出现 115 | - 系统调用:是Linux内核与用户层程序交互的唯一接口。提供最小的接口,需要陷入内核态运行。不可移植。 116 | - 库函数:依赖系统调用,是对系统调用的封装和组合,提供较为复杂的功能。可移植。 117 | 118 | 17. 例子和缓存IO的关系要掌握 119 | 120 | 18. **内核定义,基本功能** 121 | 122 | - 操作系统是一系列程序的集合,最重要的部分构成内核 123 | - 单内核/微内核 124 | - 单内核又称宏内核,是一个整体,可以分成模块,运行时是一个独立的二进制文件,模块间通过直接调用函数进行通信 125 | - 微内核的各个部分作为独立的进程在特权模式下运行,通过消息传递进行通信 126 | - Linux内核的能力 127 | - 文件管理,内存管理,进程管理,抢占式多线程支持,多处理器支持 128 | - Linux区别于其他UNIX商业内核的优点 129 | - 单内核,模块支持 130 | - 免费,开源 131 | - 支持多种CPU,硬件支持能力非常强的 132 | - Linux开发者都是非常出色的程序员 133 | - 通过学习Linux内核可以了解现代操作系统的实现原理 134 | 135 | 19. **加载.ko 模块** 136 | 137 | 操作模块 138 | 139 | - 底层:`insmod`、`rmmod` 140 | - 高层:`modprobe`、`modprobe -r` 141 | - `moddep`、`lsmod`、`modinfo` 142 | 143 | 20. **四点注意点** 144 | 145 | * 不能使用 c 库开发驱动程序 146 | * 没有内存保护机制 147 | * 小内核栈 148 | * 并发上的考虑 149 | 150 | 151 | 152 | 153 | 154 | ### 二. 系统知识点 155 | 156 | #### 1. 硬盘分区方式到文件系统到VFS到系统调用API 157 | 158 | 159 | 160 | ##### 1.1 MBR 和 GPT 不同的硬盘分区方式 161 | 162 | 163 | 164 | ##### 1.2 文件系统及其原理 165 | 166 | 167 | 168 | ###### 1.2.1 文件的概念,类型,文件夹结构 169 | 170 | 171 | 172 | **文件描述符, Inode 号, 文件对象等的关系?** 173 | 174 | 175 | 176 | - 文件是数据的集合 177 | - 文件结构:字节流、记录序列(Record Sequence)、记录树(Record Tree)。Linux下为字节流。 178 | - Linux的文件类型 179 | - 普通文件(-):纯文本文件、二进制文件、数据格式文件 180 | - 字符设备文件(c, character):与设备进行交互的文件。按字符进行I/O。如:终端文件(ttyN) 181 | - 块设备文件(b, block):同字符设备文件,但按块进行I/O。如:硬盘 182 | - 套接字文件(s, socket):表示一个socket连接。可以通过这个文件来与连接的对方(peer)进行通信。 183 | - 管道文件/FIFO文件(p, pipe):用于进程间通信。一个进程可以从这个文件中读取另一个进程此前写入的数据 184 | - 符号链接文件(l, link) 185 | - 目录文件(d, directory) 186 | - 目录结构 187 | - Linux中所有的目录均包含在一个统一的、虚拟的统一文件系统(Unified File System)中。 188 | - 物理设备被抽象为文件,挂载到指定的挂载点。没有Windows下的盘符的概念 189 | - 根目录下各个文件夹的作用: 190 | - /bin:系统必要的命令的二进制文件。包含了会被会被系统管理者和用户使用的命令。大部分常用的命令都在这里。 191 | - /boot:Boot Loader相关的静态文件。包含了所有需要在系统引导阶段使用的文件(如内核镜像等)。 192 | - /dev:设备对应的虚拟文件。 193 | - /etc:系统和软件的配置文件。 194 | - /lib:必要的共享库文件(如.so)或内核模块。 195 | - /media:外部设备通用挂载点的父目录。 196 | - /mnt:临时文件系统的挂载点的父目录。 197 | - /opt:额外的应用软件包安装目录 198 | - /sbin:只有管理员可以使用的命令的二进制文件。是与系统相关的基本命令,如shutdown,reboot等 199 | - /srv:系统提供的有关服务的数据 200 | - /tmp:临时文件 201 | - /usr:Unix System Resources,不是user的简写。用于存放共享、只读的数据。子目录包括/bin,/etc,/lib,/sbin,/tmp等,与根目录下对应的目录对比,这些目录是給后来安装的软件的使用的(而不是系统自带的)。还有/include,/src等文件夹,存放系统编程所需的头文件和源码等。 202 | - /home:用户的家目录的父目录 203 | - /root:root用户的家目录 204 | 205 | ###### 1.2.2 文件系统概念和种类 206 | 207 | 208 | 209 | - 操作系统中负责存取和管理文件的部分 210 | - 一个文件及其某些属性的集合。它为这些文件的序列号提供了一个名称空间 211 | - 类型 212 | - VFS,(Virtual File System)虚拟文件系统,与以下的磁盘文件系统(即文件的分区格式不同),为底层的文件系统提供了统一的抽象 213 | - EXT2,EXT3,EXT4,FAT32,ExFAT 214 | 215 | 216 | 217 | 218 | 219 | ##### 1.3 虚拟文件系统以及相关原理 220 | 221 | 222 | 223 | ###### 1.3.1 VFS 的作用。 4种对象分别表示什么意思 224 | 225 | ​ 具体的原理去查阅 226 | 227 | - 只存在于内存中(这句话不完全准确。如有兴趣请深入理解一遍Linux的文件系统) 228 | - 四种对象 229 | - super block:超级块。一个超级块对应一个文件系统。 230 | - inode:索引节点。一个实际存在的文件实体只有一个inode。inode对象全系统共用。 231 | - dentry:目录项。一个目录项对应一个dentry,就是ls -a列出来的每一项就是一个dentry。dentry中有指向inode的指针。多个dentry可以对应同一个inode。dentry对象全系统共用。 232 | - file:文件对象。一个打开了的文件对应一个file。file中有指向dentry的指针。文件对象是进程私有的(会以copy-on-write的方式与子进程共享)。 233 | 234 | ##### 1.4 文件系统的 API 和编程 235 | 236 | ​ IO系统调用围绕文件描述符fd,一个非负整数进行。标准输入、标准输出、标准错误对应的fd分别是STDIN_FILENO(0),STDOUT_FILENO(1),STDERR_FILENO(2) 237 | 238 | - `int open(const char *pathname, int flags);` 239 | 240 | `int open(const char *pathname, int flags, mode_t mode);` 241 | 242 | `int creat(const char *pathname, mode_t mode)` 243 | 244 | pathname:文件路径 245 | 246 | flags:文件打开模式。位域。可选值O_RDONLY、O_WRONLY、O_RDWR、O_APPEND、O_TRUNC(清空文件原来的内容)、O_CREAT(如果不存在则创建)、O_EXCL(和O_CREAT一起使用时,如果原来存在则报错)、O_NONBLOCK(非阻塞模式) 247 | 248 | mode:创建文件时的权限,无符号整数,同chmod的值 249 | 250 | 返回值:文件描述符;失败时则-1 251 | 252 | - `int close(int fd)` 253 | 254 | fd:文件描述符 255 | 256 | 返回值:0;失败则-1 257 | 258 | - `ssize_t read(int fd, void *buf, size_t count);` 259 | 260 | buf:缓冲区 261 | 262 | size_t:要读取的字节数 263 | 264 | 返回值:已读取的字节数;若此次调用前已达到文件末尾,则0;出错则-1 265 | 266 | - `ssize_t write(int fd, const void *buf, size_t count);` 267 | 268 | 类比read 269 | 270 | - `off_t lseek(int fd, off_t offset, int whence)` 271 | 272 | offset:偏移量 273 | 274 | whence:SEEK_SET:相对文件头偏移+offset处(这里offset不可以为负值) 275 | 276 | ​ SEEK_CUR:相对当前位置偏移+offset处(可以为负值) 277 | 278 | ​ SEEK_END:偏移到文件末尾+offset处(可以为负值) 279 | 280 | 返回值:偏移量;失败则-1 281 | 282 | - `int dup(int oldfd);` 283 | 284 | `int dup2(int oldfd, int newfd);` 285 | 286 | dup复制一个文件文件描述符,返回新的 287 | 288 | dup2复制oldfd到newfd,之前newfd对应的文件将被关闭。 289 | 290 | 返回:新的文件描述符;出错则-1 291 | 292 | - `int fcntl(int fd, int cmd);` 293 | 294 | `int fcntl(int fd, int cmd, long arg);` 295 | 296 | `int fcntl(int fd, int cmd, struct flock *lock);` 297 | 298 | cmd: 299 | 300 | - F_DUPFD:复制文件描述符,返回新的文件描述符 301 | - F_GETFD/F_SETFD:获取/设置文件描述符标识(目前只有close-on-exec,表示子进程在执行exec族命令时释放对应的文件描述符)。 302 | - F_GETFL/F_SETFL:获得/设置文件状态标识(open/creat中的flags参数),目前只能更改O_APPEND,O_ASYNC,O_DIRECT,O_NOATIME,O_NONBLOCK 303 | - F_GETOWN/F_SETOWN:管理I/O可用相关的信号。获得或设置当前文件描述符会接受SIGIO和SIGURG信号的进程或进程组编号 304 | - F_GETLK/F_SETLK/F_SETLKW:获得/设置文件锁,设置为F_GETLK需要传入flock的指针用于存放锁信息。S_SETLK也传入flock指针表示需要改变的锁的内容,如果不能设置则立即返回EAGAIN。S_SETLKW同S_SETLK,但在无法设置时会阻塞当前进程直到成功 305 | 306 | - `int stat(const char *filename, struct *buf);` 307 | 308 | `int fstat(int fd, struct stat *buf);` 309 | 310 | `int lstat(const char *filename, struct stat *buf);` 311 | 312 | 获取文件的属性。最后一个是遇到符号链接时,能取到被链接的文件的属性(其他的只能取到链接文件自己的属性)。 313 | 314 | 返回值:0;失败则-1 315 | 316 | ``` 317 | struct stat { 318 | mode_t st_mode; 319 | ino_t st_ino; 320 | dev_t st_rdev; 321 | nlink_t st_nlink; 322 | uid_t st_uid; 323 | gid_t st_gid; 324 | off_t st_size; 325 | time_t st_atime; 326 | time_t st_mtime; 327 | time_t st_ctime; 328 | long st_blksize; 329 | long st_blocks; 330 | } 331 | ``` 332 | 333 | `st_mode`里存放了类型、权限等信息。 334 | 335 | 另外注意下,这几个`time_t`是时间戳也就是long,不是C库里那个time_t 336 | 337 | - `int access(const char *path, int mode);` 338 | 339 | 根据当前的用户ID和实际组ID测试文件的存取权限 340 | 341 | mode:R_OK,W_OK,X_OK,F_OK(文件是否存在) 342 | 343 | 返回值:0;失败则-1 344 | 345 | - `int chmod(const char *path, mode_t mode);` 346 | 347 | `int fchmod(int fd, mode_t mode);` 348 | 349 | mode与st_mode中的第九位相同。 350 | 351 | 返回值:0;失败则-1 352 | 353 | - `int chown(const char *path, uid_t owner, gid_t group);` 354 | 355 | `int fchown(int fd, uid_t owner, gid_t group);` 356 | 357 | `int lchown(const char *path, uid_t owner, gid_t group);` 358 | 359 | 更改文件的拥有者和组 360 | 361 | 返回值:0;失败则-1 362 | 363 | - `mode_t umask(mode_t mask);` 364 | 365 | 更改存取权限屏蔽字(默认为022) 366 | 367 | 返回值:之前的值 368 | 369 | - `int link(const char *oldpath, const char *newpath);` 370 | 371 | `int unlink(const char *pathname);` 372 | 373 | 创建/删除一个文件的硬链接 374 | 375 | 返回值:0;失败则-1 376 | 377 | - `int symlink(const char *oldpath, const char *newpath);` 378 | 379 | `int readlink(const char *path, char *buf, size_t bufsize);` 380 | 381 | 创建/读取符号链接的值 382 | 383 | 返回值:0;失败则-1 384 | 385 | - `int mkdir(const char *pathname, mode_t mode);` 386 | 387 | `int rmdir(const char *pathname);` 388 | 389 | 创建/删除空目录 390 | 391 | 返回值:0;失败则-1 392 | 393 | - `int chdir(const char *path);` 394 | 395 | `int fchdir(int fd);` 396 | 397 | 更改当前工作目录 398 | 399 | 返回值:0;失败则-1 400 | 401 | - `char *getcwd(char *buf, size_t size);` 402 | 403 | 获取当前工作目录 404 | 405 | 返回值:buf;失败则NULL 406 | 407 | - `DIR *opendir(const char *name);` 408 | 409 | 打开目录 410 | 411 | 返回值:DIR指针,类似FILE;失败则NULL 412 | 413 | - `int closedir(DIR *dir);` 414 | 415 | `struct dirent *readdir(DIR *dir);` 416 | 417 | `off_t telldir(DIR *dir);` 418 | 419 | `void seekdir(DIR *dir, off_t offset);` 420 | 421 | 不赘述 422 | 423 | ``` 424 | struct dirent { 425 | long d_ino; 426 | off_t d_off; 427 | unsigned short d_reclen; 428 | unsigned char d_type; 429 | char d_name [NAME_MAX + 1]; 430 | } 431 | ``` 432 | 433 | d_reclen不是文件名的长度,课件上这里是错的。表示的是这个记录的长度,计算方式:4(d_ino) + 4(d_off) + 2(d_reclen) + 1(d_type) + 1(padding) + 4N(d_name) = 12 + ceil(length_of(d_name))。d_name会自动补齐到4的倍数。如1.jpg和1234.jpg都是8,12345.jpg是12。 434 | 435 | - `int lockf(int fd, int cmd, off_t len);` 436 | 437 | cmd:指定的操作类型 438 | 439 | - F_LOCK:给文件夹互斥锁。若已被加锁则阻塞直到成功 440 | - F_TLOCK:同上,但不会阻塞,直接失败 441 | - F_ULOCK:解锁 442 | - F_TEST:测试是否上锁。未上锁则0,否则-1 443 | 444 | len:从当前位置开始要锁住多长 445 | 446 | 这个函数是对fcntl的一层封装 447 | 448 | 449 | 450 | ###### 标准I/O库 451 | 452 | 453 | 454 | 标准库中的I/O围绕FILE对象,也就是流指针进行。预定义三个流指针,即标准输入stdin,标注你输出stdout,标准错误stderr 455 | 456 | - 缓冲模式 457 | 458 | - 块缓冲(全缓冲,full buffered,block bufferd) 459 | - 行缓冲 460 | - 无缓冲 461 | 462 | - `void setbuf(FILE *stream, char *buf);` 463 | 464 | `int setvbuf(FILE *stream, char *buf, int mode, size_t size);` 465 | 466 | mode:缓冲模式,_IOFBF(全缓冲),_IOLBF(行缓冲),_IONBF(无缓冲) 467 | 468 | buf:缓冲区,如果为NULL且mode不是_IONBF,库会调用malloc分配由size指定的大小的空间 469 | 470 | 返回值:0;失败则非0 471 | 472 | - `FILE *fopen(const char *filename, const char *mode)` 473 | 474 | mode:打开的模式:"r"只读;"w"覆盖写;"a"追加;"r+"读写;"w+"读+覆盖写,且在文件不存在时自动创建;"a+"读+追加写,且在文件不存在时自动创建;"t"文本模式;"b"二进制模式。最后两个可以和之前的组合,如"rb","at+"等 475 | 476 | 返回值:流指针;失败则NULL 477 | 478 | - `int fclose(FILE *stream)` 479 | 480 | 返回值:0;失败则EOF 481 | 482 | - `int getc(FILE *fp);` 483 | 484 | `int fgetc(FILE *fp);` 485 | 486 | `int getchar(void);` 487 | 488 | `getchar`从标准输入读取。 489 | 490 | `getc`使用宏来实现的,所以要注意其参数不能有副作用。但效率会略高于`fgetc` 491 | 492 | 返回值:转换成unsigned int的char值;读取到末尾或出错则EOF 493 | 494 | - `int putc(int c, FILE *fp);` 495 | 496 | `int fputc(int c, FILE *fp);` 497 | 498 | `int putchar(int c)` 499 | 500 | 返回值:写入的字符值;出错则-1 501 | 502 | - `char *fgets(char *s, int size, FILE *stream);` 503 | 504 | `char *gets(char *s);` 505 | 506 | s:缓冲区 507 | 508 | 后者不推荐,很容易溢出 509 | 510 | 注意,会读取size - 1个字符,并在末尾添加\0。遇到文件尾或换行符会停止 511 | 512 | 返回值:缓冲区头 513 | 514 | - `int fputs(const char *s, FILE *stream);` 515 | 516 | `int puts(const char *s);` 517 | 518 | 批量写入直到第一个\0(\0本身不写入) 519 | 520 | 返回值:非负整数;出错则EOF 521 | 522 | - `size_t fread(void *buf, size_t size, size nmemb, FILE *stream);` 523 | 524 | `size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream);` 525 | 526 | size:每次读/写的字节数 527 | 528 | nmemb:总共读/写几次。也就是说总共写入的字节数是size * nmemb。**注意这里课件上的解释是错的** 529 | 530 | 返回值:成功读/写的次数 531 | 532 | - `int scanf(const char *format, ...);` 533 | 534 | `int fscanf(FILE *stream, const char *format, ...)` 535 | 536 | `int sscanf(const char *str, const char *format, ...);` 537 | 538 | 分别从标准输入,流,字符串扫描输入。注意后面的`...`是指可变参数。 539 | 540 | 返回值:正确读取的变量个数 541 | 542 | - `int printf(const char *format, ...)` 543 | 544 | `int fprintf(FILE *stream, const char *format);` 545 | 546 | `int sprintf(char *str, const char *format);` 547 | 548 | 分别格式化输出到标准输出,流,字符串(包括一个\0)。返回值为写入的字符数,包括\0。 549 | 550 | - `int fseek(FILE *stream, long int offset, int whence);` 551 | 552 | 和`lseek`差不多 553 | 554 | - `long ftell(FILE *stream);` 555 | 556 | 返回当前位置的偏移量 557 | 558 | - `void rewind(FILE *stream);` 559 | 560 | 将流指针移到文件开头 561 | 562 | - `int fgetpos(FILE *fp, fpos_t *pos);` 563 | 564 | `int fsetpost(FILE *fp, const fpos_t *pos);` 565 | 566 | 也用来获取/移动位置,向/从pos参数存放/读取位置信息。新增这两个函数是为了处理大到超出long int范围的文件 567 | 568 | 返回值:0;失败则一个非零值 569 | 570 | - `int fflush(FIILE *stream);` 571 | 572 | 返回值:0;失败则EOF 573 | 574 | - `int fileno(FILE *fp)` 575 | 576 | 获取流指针对应的文件描述符 577 | 578 | - `FILE *fdopen(int fd, const char *mode);` 579 | 580 | 用已打开的文件描述符创建一个流 581 | 582 | - `char *tmpnam(char *s);` 583 | 584 | 返回一个当前未被使用的文件名 585 | 586 | - `FILE *tmpfile(void);` 587 | 588 | 创建一个临时文件 589 | 590 | # 591 | 592 | 593 | 594 | ### 三. Linux Shell 595 | 596 | 597 | 598 | #### 1. Linux shell 命令 599 | 600 | 601 | 602 | 高级命令。 Find 要。sed 不用。grep 要掌握 603 | 604 | 605 | 606 | #### 2. Linux shell 脚本 607 | 608 | 自己能够写shell脚本。read 基本功能 609 | 610 | 引号的用法,转义和区别 611 | 612 | 算数扩展 613 | 614 | 参数扩展不考 615 | 616 | 即时文档要求掌握 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | -------------------------------------------------------------------------------- /Linux programming/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 重点押题全都错了,今年考试太惨了。 4 | 5 | 6 | 7 | 8 | 9 | ### 一、选择题 (5 * 6=30) 10 | 11 | 12 | 13 | 1. 用户与内核的接口是什么 14 | 2. 删除文件夹的命令 15 | 3. 重定向-输出文件内容 16 | 4. 切换用户的命令 17 | 18 | 19 | 20 | ### 二、简答题(2 * 10=20) 21 | 22 | 1. 为什么Linux引入makefile?和其他脚本的区别?使用makefile编译系统有哪些?特点? 23 | 24 | 2. 硬链接与软链接的区别?(至少三点)用shell命令和函数如何创建? 25 | 26 | 27 | 28 | ### 三、编程题(15+20+15=50) 29 | 1. 看代码,是否有缓冲区溢出?如何改进? 30 | 2. 用系统调用实现输出给定文件夹中所有文件的名字 用空格隔开,并在文件夹及文本文件的输出后注上“(文件夹)”(文本文件)” 31 | 3. shell脚本编程,获得用户输入的100个整数,并输出其最大值,最小值,总和。 32 | 33 | 34 | 35 | 36 | 37 | ### 2015年试卷 38 | 39 | 1. 对于umask=022,生成文件的默认权限是。 40 | 2. Linux中可以调用文件操作函数分___和C库 函数。_ 41 | 3. 将文件按页打印的命令是 42 | 4. chmod的功能是_ 43 | 5. Linux中文件描述符的数据类型是_____。int 44 | 6. Linux中文件描述符和文件指针FlL E *的区别是什么? (9分) 45 | 7. 什么是操作系统内核?内核的主要功能是什么? (12分) 46 | 8. 比较软链接和硬链接的三点不同之处,写出shell和应用程序中创建软硬链接的命令。(15分) 47 | 9. 比较字符设备和块设备的区别,并举实例。(9分) 48 | 10. 重定向是Linux中的重要机制。试分析其使用方法、应用实例,并简述实现机制。(15分) 49 | 11. 使用C的库函数,编写一个函数void bindiff(char *fle1,char *fle2,char *fleo),将文件从fle1、fle2对应的路径中读取并逐字节比对,将相同的字节输出到fleo对应的文件中。(25分) 50 | 51 | ​ 52 | 53 | ### 2016年试卷 54 | 55 | 1. 用户与内核的接口是什么(6分) 56 | 57 | 2. 删除文件夹的命令(6分 58 | 3. 重定向-输出文件内容(6分) 59 | 4. 切换用户的命令(6分) 60 | 5. 为什么Linux引入makefile?和其他脚本的区别?使用makefle编译系统有哪些?特点? (10分) 61 | 6. 硬链接与软链接的区别? (至少三点) 用shell命令 和函数如何创建? (10分) 62 | 7. 看代码,是否有缓冲区溢出?如何改进? (15分) 63 | 8. 用系统调用实现输出给定文件夹中所有文件的名字用空格隔开,并在文件夹及文本文件的输出后注上“(文件夹)”“(文本文件)”(20分) 64 | 9. shel脚本编程,获得用户输入的100个整数,并输出其最大值,最小值,总和。(15分) 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Linux programming/deep-understanding.md: -------------------------------------------------------------------------------- 1 | ## 关于一些文件概念的深入理解 2 | 3 | -------------------------------------------------------------------------------- /Linux programming/io_example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | int main() 12 | { 13 | /** 14 | * 读入缓冲定义 15 | */ 16 | 17 | char buf[1024]; 18 | char w_buf[] = {'a','s'}; 19 | 20 | /** 21 | * int open(const char *, int, ...) 22 | // * 1. 文件名 2. 打开方式 3. 权限 23 | // * 返回: 文件描述符(是针对进程的) 24 | // */ 25 | // 26 | int fd = open("../data", O_RDWR, S_IRUSR); 27 | 28 | /** 29 | * lseek(int fildes, off_t offset, int whence); 30 | */ 31 | 32 | off_t cur = lseek(fd, 2, SEEK_SET); 33 | 34 | /** 35 | * ssize_t read(int, void *, size_t) 36 | * 1. 文件描述符 2. 读入位置 3. 目标读入大小 37 | * 返回值, 实际读入大小。 出现异常就是 返回 -1 38 | */ 39 | long r_count = read(fd, buf, 1024); 40 | 41 | /** 42 | * ssize_t write(int __fd, const void * __buf, size_t __nbyte) 43 | * 1. 文件描述符 2. 写入的内容 3. 写入的大小(自己控制,不会自己停止) 44 | * 返回值: 实际写入的大小 45 | */ 46 | long w_count = write(fd, w_buf, 2); 47 | 48 | 49 | int dup_fd; 50 | /** 51 | * dup 出的文件描述符 会是完全相同的,所有的操作都会进行共享 52 | */ 53 | dup_fd = dup(fd); 54 | 55 | /** 56 | * 和 dup 操作的区别是可以指定,先关闭后重新打开 57 | */ 58 | int dp = dup2(fd, dup_fd); 59 | 60 | /** 61 | * fcntl 感觉比较复杂,应该不会直接去考 62 | * int fcntl(int fd, int cmd); 63 | * fd: 文件描述符 64 | * cmd:{ 65 | * F_DUPFD: 复制文件描述符 66 | * F_GETFD: 67 | * F_SETFD: 68 | * F_GETFL 69 | * F_SETFL: 70 | * 其他都是文件锁相关内容比较多 71 | * } 72 | */ 73 | int fc = fcntl(fd, F_GETFD); 74 | 75 | /** 76 | * 这是一个系统调用, 实现起来也比较麻烦,感觉也不会直接去考 77 | * int ioctl(int, unsigned long, ...); 78 | */ 79 | 80 | 81 | /** 82 | * 下面系统库函数 API 部分 83 | * getChar() 需求重载 stdin 84 | */ 85 | FILE* file = fopen("../data","r+"); 86 | 87 | int temp; 88 | while ((temp = getc(file)) != EOF) { 89 | if (putc(temp, stdout) == EOF) 90 | { 91 | break; 92 | } 93 | } 94 | 95 | char s[1024]; 96 | while(fgets (s, 1024, file) !=NULL ) { 97 | if(s[0] == '\n'){ 98 | cout << "???" << endl; 99 | } 100 | fputs(s, stdout); 101 | } 102 | 103 | char f_buf[1024]; 104 | 105 | 106 | while (1) 107 | { 108 | memset(buf, 0, sizeof(buf)); 109 | size_t rc = fread(f_buf, sizeof(char), sizeof(buf), file); 110 | if (rc <= 0) 111 | break; 112 | fwrite(f_buf, 1, rc, stdout); 113 | } 114 | 115 | 116 | 117 | int a; 118 | scanf("%d", &a); 119 | sscanf("12123","%d", &a); 120 | 121 | ftell(file); 122 | 123 | fpos_t position = 1; 124 | fgetpos(file, &position); 125 | 126 | fflush(file); 127 | 128 | int n = fileno(file); 129 | 130 | FILE* another = fdopen(n, "w"); 131 | 132 | /** 133 | * 产生临时文件 134 | */ 135 | FILE* tmp_file = tmpfile(); 136 | 137 | /** 138 | * 一系列文件夹操作测试 139 | */ 140 | DIR* dir = opendir("CMAKeFiles"); 141 | 142 | cout << mkdir("test", S_IRWXU) << endl; 143 | 144 | char global_pwd[1024]; 145 | 146 | cout << getcwd(global_pwd, sizeof(global_pwd)) << " " << global_pwd << endl; 147 | 148 | cout << chdir("test") << endl; 149 | 150 | cout << getcwd(global_pwd, sizeof(global_pwd)) << " " << global_pwd << endl; 151 | 152 | cout << fchdir(dir->__dd_fd) << endl; 153 | 154 | cout << getcwd(global_pwd, sizeof(global_pwd)) << " " << global_pwd << endl; 155 | 156 | chdir(".."); 157 | 158 | cout << rmdir("test") << endl; 159 | 160 | /** 161 | * 三个 API, 几类对象一定要弄清 162 | */ 163 | dir = opendir("CMAKeFiles"); 164 | struct dirent *entry; 165 | while ( (entry = readdir(dir)) != NULL ) { 166 | struct stat info{}; 167 | lstat(entry->d_name, &info); 168 | if ( S_ISDIR(info.st_mode) ){ 169 | cout << "dir"; 170 | } 171 | else{ 172 | cout << "not"; 173 | } 174 | } 175 | 176 | /** 177 | * 后面的文件锁操作还是 fcntl 里面的 178 | * 179 | */ 180 | 181 | /** 182 | * Linux 文件中的锁 183 | * 首先是共享锁和排他锁之间的关系,只有共享锁可以相互进行共享 184 | * 劝告锁,不能主动阻拦,需要去检查判断。 185 | * 强制锁,被锁住的文件在其他文件访问时会被强制阻拦 186 | * 记录锁, 用于锁住文件的某个部分。 187 | * 188 | * Linux 锁用的API 还是 fcntl 和 flock 189 | */ 190 | 191 | 192 | 193 | fclose(file); 194 | 195 | 196 | /** 197 | * 关闭文件, 正常是0, 异常是-1 198 | */ 199 | int sig = close(fd); 200 | 201 | } 202 | 203 | 204 | -------------------------------------------------------------------------------- /Linux programming/key-point.md: -------------------------------------------------------------------------------- 1 | # Linux 重点 2 | 3 | 每一个知识点都进行了评估,前面代表重要程度(考试概率),后面代表掌握的难易程度。 度量是 S, M, H。 4 | 5 | 参照了体系结构中的评估方法 (现学现用….) 6 | 7 | [TOC] 8 | 9 | 10 | 11 | ##### 1. linux 作者 (S, S) 12 | 13 | Linux Torvalds 14 | 15 | ##### 2.Linux 发行版有哪些 (S, S) 16 | 17 | Red Hat, Debain, SuSe, Mandrake, Redflag, Ubuntu。。。 18 | 19 | ##### 3. MBR 和 GPT 解析(单独拿出文件) (S, H) 20 | 21 | 关键是支持大小等不一样 22 | 23 | ##### 4. 文件系统和VFS的概念. (H,H) 24 | 25 | 文件系统包含了一系列文件和他们的属性的集合,提供了一个对于文件的命名空间。 26 | 27 | 严格地说,文件系统是一套实现了[数据](https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE)的存储、分级组织、访问和获取等操作的[抽象数据类型](https://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E6%95%B8%E6%93%9A%E9%A1%9E%E5%9E%8B)(Abstract data type)。 28 | 29 | 文件系统软件来负责将这些块组织为文件和目录,并记录哪些块被分配给了哪个文件,以及哪些块没有被使用。 30 | 31 | VFS 对各个文件系统做出了统一的接口,对外提供本操作系统的文件库函数和系统调用等。 这个在后面单独讲。 32 | 33 | ##### 5. Linux 磁盘分区 (M,H) 34 | 35 | `/boot` 分区 36 | 37 | `/` 分区 38 | 39 | ##### 6. boot loader 引导程序(S,H) 40 | 41 | 加载和启动 Linux 内核 42 | 43 | 1. 可以 向 linux 内核传递参数 44 | 2. 可以选择性的加载初始化 root 硬盘 45 | 3. 也可以加载其他的操作系统 46 | 47 | GRUB 存储在 boot loader 中的操作系统。 48 | 49 | 尤其注意安装双系统的时候 后安装的操作系统必须提供能够加载之前操作系统的引导程序才可能形成正确的双系统。 50 | 51 | ##### 7. 虚拟终端(S,M) 52 | 53 | 一台电脑只有一个console,但是可以划分出7个不同的虚拟终端。 54 | 55 | 虚拟终端是 console 模拟出来的。 56 | 57 | 注: 关于此问题下的另一个可能概念 shell , shell 是核外软件模拟出来的,通过shell 的方式建立的终端应该不算是 虚拟终端。 所以 ssh 可以开十分多个。 58 | 59 | ##### 8. 基本命令(M,M) 60 | 61 | `ls -l` 62 | 63 | 文件类别, 权限(3种), 链接数,拥有者,拥有者组,大小,最后修改时间,名称 64 | 65 | 66 | 67 | `chomd filename` 68 | 69 | Who: u,g,o,a 70 | 71 | Operator: +,-,== 72 | 73 | What: r,x,w 74 | 75 | 或者采用数字方式: x = 1, w = 2, r = 3 对三种角色设置权限 76 | 77 | 78 | 79 | `su` 切换用户,好像这个会很经常考 80 | 81 | `passwd` 修改密码 82 | 83 | 84 | 85 | 86 | 87 | ##### 9. 文件类型 (M,H) 88 | 89 | 文件结构包含字节流、记录序列(Record Sequence)、记录树(Record Tree),Linux下文件为字节流。Linux中所有的目录均包含在一个统一的、虚拟的统一文件系统(Unified File System)中。物理设备被抽象为文件,挂载到指定的挂载点。没有Windows下的盘符的概念 90 | 91 | 92 | 93 | - 普通文件(-):纯文本文件、二进制文件、数据格式文件 94 | - 字符设备文件(c, character):与设备进行交互的文件。按字符进行I/O。如:终端文件(ttyN) 95 | - 块设备文件(b, block):同字符设备文件,但按块进行I/O。如:硬盘 96 | - 套接字文件(s, socket):表示一个socket连接。可以通过这个文件来与连接的对方(peer)进行通信。 97 | - 管道文件/FIFO文件(p, pipe):用于进程间通信。一个进程可以从这个文件中读取另一个进程此前写入的数据 98 | - 符号链接文件(l, link) 99 | - 目录文件(d, directory) 100 | 101 | 102 | 103 | ##### 10. 进程的概念(S,S) 104 | 105 | 进程是一个正在执行的程序实例。由执行程序、它的当前值、状态信息以及通过操作系 106 | 统管理此进程执行情况的资源组成。 107 | 108 | 109 | 110 | ##### 11. Linux 层次图(M,H) 111 | 112 | 就不在这里放了 113 | 114 | 115 | 116 | ##### 12. 重定向和管道 (H,H)非常可能考 117 | 118 | 已经单独写了一个文件说明 119 | 120 | 121 | 122 | ##### 13. 环境变量 (S,M) 123 | 124 | - env:显示所有环境变量 125 | - echo $VAR_NAME:显示某个变量的值 126 | - set:显示本地定义的变量 127 | - export:将用户变量(只在当前shell可见变量)输出为环境变量 128 | - 常用环境变量 129 | - HOME:当前用户的家目录 130 | - PATH:可执行文件的搜索路径 131 | - TERM:终端的类型 132 | - UID:当前用户的UID 133 | - PWD:当前工作目录 134 | - PS1:主提示符 135 | - PS2:副提示符(换行) 136 | - IFS:输入区分隔符 137 | 138 | 139 | 140 | ##### 14. shell 是什么 (H,M) 141 | 142 | **用户和操作系统之间的接口,作为核外程序而存在。** (这句话好像很常考,ppt上有两个图生动形象的说明这点) 143 | 144 | 145 | 146 | ##### 15. shell 例子 (S,M) 147 | 148 | ash, bash, sh, csh, tcsh, ksh 。。。 149 | 150 | 151 | 152 | ##### 16. shell 的双重角色(M,M) 153 | 154 | 命令提示符(调用者) + 独立程序解释语言 155 | 156 | 1. 命令解释程序:打印提示符;得到命令行;解析命令;查找文件;准备参数;执行命令 157 | 2. 独立的程序设计语言解释器。 158 | 159 | 160 | 161 | ##### 17. shell 脚本执行方式(H,M) 162 | 163 | 让 shell 来做的就不需要权限,自己运行的就要权限 164 | 165 | 1. `sh/bash/csh/some_bash script_file` **打开一个subshell**去读取、执行,脚本不需要有"**执行权限**" 166 | 167 | 2. `chmod +x script_file` **打开一个subshell**去读取、执行,需要有"**执行权限**" 168 | 169 | `./scirpt_file` 170 | 171 | 3. `source script_file`或`. script_file` 在**当前shell内**去读取、[执行a.sh](http://xn--a-g64b923i.sh/),而a.sh不需要有"**执行权限**" 172 | 173 | 174 | 175 | ##### 18. shell 中引号的用法和一些转义,参数扩展 (H,H) 176 | 177 | * 单引号内的所有字符都保持它本身字符的意思,而不 会被bash进行解释,例如,\$ 就是 \$本身而不再是bash的变量引用符;\就是\本身而不再是bash的转义字符。 178 | 179 | * 除了$、``(不是单引号)和\外,双引号内的所有字符将保持字符本身的含义而不被bash解释。 180 | * 算数扩展: $(()) 进行算数运算,否则相加是字符串拼接 181 | 182 | 183 | 184 | ##### 19. shell 编程能力(H,H) 一定会考 185 | 186 | * `read` 语法: read 变量名 直接写入变量名内 187 | * boolean expression,`test` 或者 `[]` 语法 188 | * `-eq`, `-ne`, `gt`,`ge`,`lt`,`le` 等表达式条件判断 189 | * If 后加 fi, case 后加 esac ,所有在 c 中需要大括号的这里用反字符转 190 | * case ** in; choice) ;; choice) ;; *);; 191 | * for in 语法 192 | * while do done 语法 193 | * util do done 语法 194 | * select 语法,自动生成菜单 195 | * 函数用大括号的形式 196 | 197 | 198 | 199 | ##### 20. 编译流程 和 GCC 参数 (S,M) 200 | 201 | ###### 编译流程: 202 | 203 | 源文件(.c/.cpp)–预处理–>纯C代码–编译(cc)–>汇编程序(.s)–汇编(as)–>目标文件(.o)–链接(ld)-(.a文件)->可执行文件 204 | 205 | ###### GCC 参数(只用于编译和链接) 206 | 207 | - -E:只进行预处理 208 | - -S:只进行预处理、编译 209 | - -c:预处理、编译、汇编 210 | - -o [output_file]:指定输出文件名 211 | - -g:产生符号文件(可用于调试工具) 212 | - -On:优化等价,n可以取0,1,2,3 213 | - -Wall:显示所有警告信息 214 | - -Idir:指定额外的头文件搜索路径 215 | - -Ldir:指定额外的库文件搜索路径 216 | - -lname:指定链接时搜索的库文件(name要去掉lib,如要链接pthread,pthread的静态库名为libpthread.a,则参数写成-lpthread) 217 | - -D**MACROT**[=DEFN]:定义宏 218 | 219 | 220 | 221 | ##### 21. 静态库和动态库(M,M) 222 | 223 | 静态库:是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为”.a”。 224 | 225 | 动态库:与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为”.so”,gcc/g++在编译时默认使用动态库。无论静态库,还是动态库,都是由.o文件创建的。 226 | 227 | 228 | 229 | ##### 22. 硬链接和软连接的区别(H,M) 230 | 231 | - 软连接 232 | - 是确确实实存在的一个文件,有自己的inode号 233 | - 文件中存放被链接的文件的路径 234 | - 可以跨越文件系统 235 | - 对应系统调用symlink 236 | - 硬链接 237 | - 与被链接的文件共享同一个inode,dentry不同 238 | - 不能跨越文件系统 239 | - 对应系统调用link 240 | 241 | 242 | 243 | ##### 23. 能够读懂 makefile (M,H) 可能会考 244 | 245 | 1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。 246 | 2. 如果找到,它会找文件中的第一个目标文件(target)。 247 | 3. 如果文件不存在,或是所依赖的后面的 .o 文件的文件修改时间要比这个文件新,那么,他就会执行后面所定义的命令来生成这个文件。 248 | 4. 如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。 249 | 250 | 251 | 252 | ##### 24. 虚拟文件系统 (H,H) 253 | 254 | 虚拟: 只在内存中 255 | 256 | 组件: 257 | 258 | * 超级块: 一个超级块对应一个文件系统 259 | * i-node 对象: 索引节点。一个实际存在的文件实体只有一个inode。inode对象全系统共用。 260 | * 文件对象: 文件对象。一个打开了的文件对应一个file。file中有指向dentry的指针。文件对象是进程私有的(会以copy-on-write的方式与子进程共享)。 261 | * dentry 对象: 目录项。一个目录项对应一个dentry,就是ls -a列出来的每一项就是一个dentry。dentry中有指向inode的指针。多个dentry可以对应同一个inode。dentry对象全系统共用。 262 | 263 | 264 | 265 | ##### 25. 系统调用和库函数的区别 (H,M) 266 | 267 | 都以C函数的形式出现 268 | 269 | 系统调用:Linux内核的对外接口; 用户程序和内核之间唯一的接口; 提供最小接口 270 | 271 | 库函数:依赖于系统调用; 提供较复杂功能。例:标准I/O库 272 | 273 | 274 | 275 | 系统调用中没有实现标准的 缓存, 但是标准的IO实现了这一点,是有缓存的。 276 | 277 | 278 | 279 | ##### 26. 系统调用函数 (H,H) 每一个函数会再单独列一个优先级 280 | 281 | * `open`, `close`, `creat` 肯定不会重点考 (S,S) 282 | * `dup` `dup2` 要用到 (H,M) 很可能要写重定向. (H, M ) 283 | * `read` `write` 绝对会考 … (H, M) 284 | * `Iseek` 优先级相对低 (M , H ) 285 | * `fcntl` 这个太难了,只会一个简单的把 (S,H) 286 | * `ioctl` 更难… 不会考 (S, M ) 287 | 288 | 289 | 290 | ##### 27. 标准 IO 库 (H,H) 每个函数单独列优先级 291 | 292 | * `fopen`, `fclose` (S,S) 293 | * `getc`, `fgetc`, `getchar` ,`putc`, `fputc`, `putchar` (M,M) 294 | * `fgets`, `gets` ,`fputs`, `puts`(M,M) 295 | * `fread`, `fread` (M,M) 296 | * `scanf`, `fscanf` , `sscanf`,`printf`, `fprintf` , `sprintf` (M ,S) 297 | 298 | 299 | 300 | ##### 28. 文件夹操作 API (M,H) 比较复杂,(最新消息,不考) 301 | 302 | * `int stat(const char *filename, struct stat *buf);` 303 | 304 | `int fstat(int filedes, struct stat *buf);` 305 | 306 | `int lstat(const char *file_name, struct stat *buf);` 307 | 308 | (H, H) 309 | 310 | 311 | 312 | * `int chdir(const char *path)` 313 | 314 | `char *getcwd(char *buf, size_t size);` 315 | 316 | `DIR *opendir(const char *name);` 317 | 318 | `struct dirent *readdir(DIR *dir)` 319 | 320 | (M, H) 321 | 322 | ##### 29 内核的定义 (M,S) 323 | 324 | 操作系统是一系列程序的集合,其中最重要的部分构成了内核, 325 | 326 | Linux内核的能力: 内存管理,文件系统,进程管理,多线程支持,抢占式,多处理支持等。 327 | 328 | 329 | 330 | ##### 30. 内核驱动模块 (S, M) 331 | 332 | 1. 许多常见驱动的源代码集成在内核源码里 333 | 2. 也有第三方开发的驱动,可以单独编译成模块.ko 334 | 3. 编译需要内核头文件的支持 335 | 336 | 337 | 338 | ##### 31. 模块加载相关命令 (M, M) 339 | 340 | 底层命令 341 | 342 | * insmod 343 | * rmmod 344 | 345 | 高层命令 346 | 347 | * modprobe 348 | * modprobe -r (有依赖功能) 349 | 350 | 模块的依赖 351 | 自动按需加载 352 | 自动按需卸载 353 | 354 | * moddep 355 | * lsmod 356 | * modinfo 357 | 358 | 359 | 360 | ##### 32. 一些注意点(M,M) 361 | 362 | - 不能用C库 363 | - 没有内存保护 364 | - 小内核栈 365 | - 要考虑并发 366 | 367 | 368 | 369 | ##### 33. 遗漏点: 和重点命令实现相关的API (H,M) 370 | 371 | 372 | 373 | ###### 文件权限 374 | 375 | **chmod()会依参数mode 权限来更改参数path 指定文件的权限。** 376 | 377 | `int chmod(const char *path, mode_t mode);` 378 | 379 | 380 | 381 | ###### 软连接和硬链接 382 | 383 | **硬链接建立** 384 | 385 | `int link(const char *oldpath, const char *newpath);` 386 | 387 | **去除链接(包括两种)** 388 | 389 | `int unlink(const char *pathname);` 390 | 391 | **软链接建立** 392 | 393 | `int symlink(const char *oldpath, const char *newpath);` 394 | 395 | **将参数path的符号连接内容存到参数buf所指的内存空间** 396 | 397 | `int readlink(const char *path, char *buf, size_t bufsiz);` 398 | 399 | 400 | 401 | ###### 重定向 402 | 403 | `int dup2(int odlfd, int newfd);` 404 | 405 | `int dup(int oldfd);` 406 | 407 | 408 | 409 | -------------------------------------------------------------------------------- /Linux programming/main.cpp: -------------------------------------------------------------------------------- 1 | #define _POSIX_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace std; 16 | 17 | struct message{ 18 | int lines; 19 | int words; 20 | int size; 21 | }message; 22 | 23 | map ls_param; 24 | map wc_param; 25 | char global_pwd[PATH_MAX]; 26 | string date[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; 27 | 28 | struct stat getInfo(string cwd, string name) { 29 | struct stat info{}; 30 | string current = cwd + "/" + name; 31 | char file_pos[PATH_MAX]; 32 | strcpy(file_pos, current.c_str()); 33 | stat(file_pos, &info); 34 | return info; 35 | } 36 | 37 | void read(string filename){ 38 | message.lines = 0, message.words = 0; 39 | 40 | char file_pos[PATH_MAX]; 41 | strcpy(file_pos, filename.c_str()); 42 | 43 | FILE *fp; 44 | fp = fopen(file_pos,"r"); 45 | char ch; 46 | int flag = 0; 47 | while((ch = fgetc(fp))!=EOF){ 48 | 49 | if(ch == '\n'){ 50 | message.lines ++; //行数加1 wc -l 51 | } 52 | if(ch == '\t' || ch == ' ' || ch == '\n'){ 53 | flag = 0; //计算单词数 wc -w 54 | continue; 55 | } 56 | else{ 57 | if(flag == 0){ 58 | message.words++; //计算单词数 wc -w 59 | flag = 1; 60 | } 61 | } 62 | } 63 | message.size = getInfo(global_pwd,filename).st_size; //文件字节大小 wc -c 64 | fclose(fp); 65 | } 66 | 67 | string build_authorize(struct stat info){ 68 | string result = ""; 69 | if (S_ISREG(info.st_mode)) 70 | result += "-"; 71 | else if (S_ISDIR(info.st_mode)) 72 | result += 'd'; 73 | else if (S_ISBLK(info.st_mode)) 74 | result += 'b'; 75 | else if (S_ISCHR(info.st_mode)) 76 | result += 'c'; 77 | else if (S_ISFIFO(info.st_mode)) 78 | result += 'p'; 79 | else if (S_ISLNK(info.st_mode)) 80 | result += 'l'; 81 | else if (S_ISSOCK(info.st_mode)) 82 | result += 's'; 83 | else { 84 | result += '?'; 85 | } 86 | result += (info.st_mode & S_IRUSR) ? "r" : "-"; 87 | result += (info.st_mode & S_IWUSR) ? "w" : "-"; 88 | result += (info.st_mode & S_IXUSR) ? "x" : "-"; 89 | result += (info.st_mode & S_IRGRP) ? "r" : "-"; 90 | result += (info.st_mode & S_IWGRP) ? "w" : "-"; 91 | result += (info.st_mode & S_IXGRP) ? "x" : "-"; 92 | result += (info.st_mode & S_IROTH) ? "r" : "-"; 93 | result += (info.st_mode & S_IWOTH) ? "w" : "-"; 94 | result += (info.st_mode & S_IXOTH) ? "x" : "-"; 95 | return result; 96 | } 97 | 98 | void print_file(vector filenames, string cwd){ 99 | vector stats; 100 | 101 | int total = 0; 102 | for (const auto &filename : filenames) { 103 | struct stat info = getInfo(cwd, filename); 104 | stats.push_back(info); 105 | total += info.st_blocks; 106 | } 107 | if(ls_param['l'] && !filenames.empty()) 108 | cout << "total "<< total << endl; 109 | 110 | for(int i = 0; i < filenames.size() ; i++){ 111 | 112 | struct stat info = stats[i]; 113 | 114 | if(ls_param['i']){ 115 | cout << info.st_ino << "\t"; 116 | } 117 | 118 | if(ls_param['l']){ 119 | struct tm *tmp_time = localtime(&info.st_ctime); 120 | cout << build_authorize(info); 121 | cout << "\t" << info.st_nlink << "\t" << info.st_uid << "\t" << info.st_gid << "\t" << info.st_size; 122 | cout << "\t" << date[tmp_time -> tm_mon] << "\t" << tmp_time -> tm_mday << "\t" < tm_hour << ":" << tmp_time -> tm_min<<"\t"; 123 | } 124 | 125 | cout << filenames[i]; 126 | if(i != filenames.size() -1) { 127 | if (ls_param['l']) cout << endl; 128 | else cout << " "; 129 | }else cout << endl; 130 | } 131 | } 132 | 133 | 134 | vector filter(vector filenames){ 135 | vector vec; 136 | for(int i = 0; i < filenames.size(); i++){ 137 | if(filenames[i][0] != '.'){ 138 | vec.push_back(filenames[i]); 139 | } 140 | } 141 | return vec; 142 | } 143 | 144 | vector getName(string path){ 145 | vector result; 146 | DIR* target = opendir(path.c_str()); 147 | struct dirent * dp; 148 | while ((dp = readdir(target)) != NULL) { 149 | result.push_back(dp->d_name); 150 | } 151 | if(!ls_param['a']){ 152 | result = filter(result); 153 | } 154 | return result; 155 | } 156 | 157 | 158 | void recursive_method(string cwd){ 159 | vector next, result; 160 | vector names = getName(cwd); 161 | for(int i = 0; i < names.size() ; i++){ 162 | struct stat info = getInfo(cwd, names[i]); 163 | if(S_ISDIR(info.st_mode) && names[i] != "." && names[i] !=".."){ 164 | next.push_back(cwd + "/" + names[i]); 165 | } 166 | result.push_back(names[i]); 167 | } 168 | cout << cwd << endl; 169 | print_file(result, cwd); 170 | cout << endl; 171 | for(int i = 0; i < next.size() ;i++ ){ 172 | recursive_method(next[i]); 173 | } 174 | } 175 | 176 | 177 | void ls(vector params){ 178 | ls_param['a'] = 0, ls_param['d'] = 0, ls_param['l'] =0,ls_param['R'] = 0,ls_param['i'] = 0; 179 | for(int i = 1; i< params.size(); i++){ 180 | char *p = (char*)params[i].c_str(); 181 | int j = 0; 182 | if(*p == '-') { 183 | while (*(p + j) != '\0') { 184 | ls_param[*(p+j)] = 1; 185 | j++; 186 | } 187 | }else{ 188 | cout <<"ls " << " illegal param"<< endl; 189 | return; 190 | } 191 | } 192 | vector vec; 193 | if(ls_param['d']){ 194 | vec.push_back("."); 195 | print_file(vec,global_pwd); 196 | } else if(ls_param['R']){ 197 | recursive_method(global_pwd); 198 | } else{ 199 | vec = getName(global_pwd); 200 | print_file(vec, global_pwd); 201 | } 202 | } 203 | 204 | 205 | void wc(vector params){ 206 | wc_param['w'] = 0, wc_param['l'] = 0, wc_param['c'] =0; 207 | string fileName = ""; 208 | for(int i = 1; i< params.size(); i++){ 209 | char *p = (char*)params[i].c_str(); 210 | int j = 0; 211 | if(*p == '-') { 212 | while (*(p + j) != '\0') { 213 | wc_param[*(p+j)] = 1; 214 | j++; 215 | } 216 | }else{ 217 | fileName = params[i]; 218 | if(i!=params.size() -1){ 219 | cout << params[i+1] << "no such file " << endl; 220 | } 221 | break; 222 | } 223 | } 224 | read(fileName); 225 | 226 | bool all = false; 227 | if(!wc_param['l'] && !wc_param['w'] && !wc_param['c']){ 228 | all = true; 229 | } 230 | 231 | if(wc_param['l'] || all) 232 | cout << message.lines << "\t"; 233 | if(wc_param['w'] || all) 234 | cout << message.words << "\t" ; 235 | if(wc_param['c'] || all) 236 | cout << message.size << "\t"; 237 | 238 | cout << fileName< vec; 244 | string result; 245 | stringstream input(command); 246 | while(input>>result) 247 | vec.push_back(result); 248 | 249 | if(vec[0] == "ls"){ 250 | ls(vec); 251 | }else if(vec[0] == "wc"){ 252 | wc(vec); 253 | }else{ 254 | cout << vec[0] << " command not found!" << endl; 255 | return; 256 | } 257 | } 258 | 259 | int main() { 260 | if (getcwd(global_pwd, sizeof(global_pwd)) == nullptr) { 261 | perror("getcwd() error"); 262 | return 1; 263 | } 264 | while(true){ 265 | string command; 266 | getline(cin, command); 267 | 268 | command.erase(0,command.find_first_not_of(" ")); 269 | command.erase(command.find_last_not_of(" ") + 1); 270 | 271 | if(command.length() > 0) 272 | handleCommand(command); 273 | if(command == "exit"){ 274 | return 1; 275 | } 276 | } 277 | } -------------------------------------------------------------------------------- /Linux programming/redirect-and-pipe.md: -------------------------------------------------------------------------------- 1 | # 关于重定向操作和管道 2 | 3 | ## 重定向 4 | 5 | **重定向操作在底层的本质上就是调用了 dup2() 函数, 把进程的文件描述符进行拷贝和覆盖。** 6 | 7 | 8 | 9 | #### 一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件: 10 | 11 | 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。 12 | 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。 13 | 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。 14 | 15 | 16 | 17 | 1. 默认情况下,command > file 将 stdout 重定向到 file,command< file 将stdin 重定向到 file。 18 | 2. 如果希望 stderr 重定向到 file,可以这样写:command 2 > file 19 | 3. 如果希望 stderr 追加到 file 文件末尾,可以这样写:command 2 >> file ;2 表示标准错误文件(stderr)。 20 | 4. 如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:command > file 2>&1 或command >> file 2>&1,为什么需要将标准错误重定向到标准输出的原因,那就归结为标准错误没有缓冲区,而stdout有。 21 | 5. 如果希望对 stdin 和 stdout 都重定向,可以这样写:command < file1 >file2 ;command 命令将stdin重定向到 file1,将stdout重定向到file2。 22 | 23 | 24 | 25 | **牢记本质上就是 一些列 顺序执行的 dup2 命令** 26 | 27 | 28 | 29 | ## 管道 30 | 31 | **管道操作的本质是把上一个操作的标注输出作为本操作的标注输入** 32 | 33 | **上一个操作的标注输出指的是上一个命令在一系列重定向操作之后的仍然会输出到 标准输出的 文件描述符** 34 | 35 | 36 | 37 | 嗯,基本的思想就是上面这样了,非常简单。 38 | 39 | 有一个十分重要的命令是 xargs 40 | 41 | 42 | 43 | **xargs 的出现的原因是很多命令并不是从标准输入读入的,而是使用命令行参数的形式** 44 | 45 | **xargs 就是可以把 标准输入的内容变成命令行参数** 46 | 47 | 48 | 49 | **xargs 读入标准输入,以空格或者换行作为分隔 区分参数。 然后放到后面的命令中** 50 | 51 | **因为很多命令都是支持同时批量输入参数的,如果是不支持的,也可以设置每次输入进几个参数** 52 | 53 | 54 | 55 | ## Find 命令和 grep 命令 56 | 57 | find 操作的语法如下,一般后接管道完成功能 58 | 59 | ``` 60 | find path -option [ -print ] [ -exec -ok command ] {} \; 61 | ``` 62 | 63 | grep 一般前接管道完成功能 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 南软本科几个课程的期末复习资料 2 | 3 | -------------------------------------------------------------------------------- /Software-Architecture/1. general.md: -------------------------------------------------------------------------------- 1 | ## 软件体系结构基本概念 2 | 3 | 4 | 5 | ### 1. 软件体系结构的定义 6 | 7 | 8 | 9 | The software architecture of a program or computing system is the structure or structures of the system, which comprise software elements, the externally visible properties of those elements, and the relationships among them. ( SEI ) 10 | 11 | **KeyWord: structure, element, property, relation** 12 | 13 | The fundamental organization of a system, emboied in its components, their relationships to each other and the environment, and principles governing its design and evolution. ( IEEE ) 14 | 15 | **KeyWord: organzation, compnents, relationship, principle** 16 | 17 | 18 | 19 | **上面一般取第一个就可以** 20 | 21 | 22 | 23 | ### 2. 软件架构师的工作 ? 24 | 25 | 1. Liaison 协调各方,沟通交流 26 | 2. Software Engineering 软件工程的基本技能 27 | 3. Technology Knowledge。软件开发技术的基本知识 28 | 4. Risk Management。 风险管理能力 29 | 30 | 31 | 32 | ### 3. 软件架构的来源 ? 33 | 34 | NFRs, ASRs, Quality Requirements, Stakeholders, Organisations, Technical Environments 35 | 36 | 1. NFRs, 非功能需求,一般包括约束和质量属性 37 | 2. Architecture Significant Requirement 架构攸关需求。 38 | 3. Quality Requirements. 在功能需求的基础上需要满足的特征 39 | 4. Stakeholders 系统的利益相关者 40 | 5. Organisations 开发组织 41 | 6. Techinal Environments 技术环境 42 | 43 | 不不仅仅局限于需求,可能是商业和技术决定的集合 44 | 45 | ### 4. 架构视图 46 | 47 | Modern systems are frequently **too complex to grasp all at once**. Instead, we **restrict our attention** at any one moment to one (or a small number) of the software system’s structures. To communicate meaningfully about an architecture, we must make clear which structure or structures we are 48 | discussing at the moment—which view we are taking of the architecture. 49 | 50 | The views are used to describe the system from the viewpoint of different stakeholders, such as end-users, developers, system engineer, and project managers. 51 | 52 | #### 4.1 Logical view 53 | 54 | The logical view is concerned with the functionality that the system provides to end-users. 55 | 56 | UML diagrams used to represent the logical view include class diagrams and state diagrams。 57 | 58 | **describes architecturally significant elements of the architecture and the relationships between them.** 59 | 60 | #### 4.2 Process view 61 | 62 | The process view deals with the dynamic aspects of the system, explains the system processes and how they communicate, and focuses on the runtime behavior of the system. The process view addresses concurrency, distribution, integrators, performance, and scalability, etc. 63 | 64 | UML diagrams to represent process view include the activity diagram. 65 | 66 | **Concurrency and communications elements of an architecture** 67 | 68 | #### 4.3 Physical view 69 | 70 | The physical view depicts the system from a system engineer's point of view. It is concerned with the topology of software components on the physical layer as well as the physical connections between these components. This view is also known as the deployment view. 71 | 72 | UML diagrams used to represent the physical view include the deployment diagram. 73 | 74 | **how the major processes and components are mapped on to the applications hardware** 75 | 76 | #### 4.4 Development view 77 | 78 | The development view illustrates a system from a programmer's perspective and is concerned with software management. This view is also known as the implementation view. It uses the UML Component diagram to describe system components. 79 | 80 | UML Diagrams used to represent the development view include the Package diagram. 81 | 82 | **captures the internal orgnazition of software components ** 83 | 84 | #### 4.5 Architecture use cases 85 | 86 | The description of an architecture is illustrated using a small set of use cases , or scenarios, which become a fifth view. The scenarios describe sequences of interactions between objects and between processes. They are used to identify architectural elements and to illustrate and validate the architecture design. They also serve as a starting point for tests of an architecture prototype. This view is also known as the use case view. 87 | 88 | **capture the requirements for architecture, related to more than one particular view** 89 | 90 | 91 | 92 | 加粗部分是老师ppt上的描述,其他是维基百科上的描述 93 | 94 | 以及为什么 类图是 end-user 视角, 包图就是程序员视角??? 95 | 96 | 97 | 98 | ### 5. 架构活动和过程 99 | 100 | #### 5.1 架构活动 101 | 102 | 1. Creating the **business case** for the system 103 | 2. understanding the **requirements** 104 | 3. **Creating** and selecting architecture 105 | 4. **Communicating** the architecture (Stakeholders, developers) 106 | 5. **Analysing** or **evaluating** the architecture 107 | 6. **Implementing** the architecture 108 | 7. Ensuring **conformance** to an architecture. 109 | 110 | #### 5.2 架构过程 111 | 112 | 1. Specifying ASRs 113 | 2. Architecure design 114 | 3. Documenting 115 | 4. Architecture Evaluating 116 | 117 | 最简单的描述,还有很多细节参照 ppt 上的相关描述 118 | 119 | 120 | 121 | ### 6. 软件架构知识领域 122 | 123 | #### 6.1 软件设计基本概念 124 | 125 | 1. 总体设计概念 126 | 2. 软件开发生命周期: 需求,设计,编码,测试 127 | 3. 设计过程(角色,活动,产品) 128 | 4. 软件设计中的可用技术 129 | 130 | #### 6.2 核心技术 131 | 132 | 1. 并发 133 | 2. 控制和事件处理,分派 134 | 3. 异常处理 135 | 136 | #### 6.3 软件结构和架构 137 | 138 | 1. 软件结构和视图 139 | 2. 架构风格和架构模式 (微服务) 140 | 3. 设计模式 141 | 142 | #### 6.4 软件设计方法 143 | 144 | 1. 架构方法 (ADD 设计) 145 | 2. 设计方法 (动态系统开发) -------------------------------------------------------------------------------- /Software-Architecture/10. design-problem.md: -------------------------------------------------------------------------------- 1 | # 设计题 2 | 3 | Dstributed Cache Updates. Figure I bclow shows a dstributed applocation with caches to improve its runtime performance. An online service system provides its clients access to their Bill Staement infomation (BSI). The database stores BSI for clients. During a session,a client may require the; BSI several times In order to improve the performance, the BSI information for a particular client is cached. If the cache is loaded, then the BSI can be directly returned back to the client without access to the database. There are N servers clustered to serve the requests from clients. The Server is load-balanced, and each time one server is scheduled for one client request. All the caches on N servers need ti ssynchronize their states. If the client request changes the states od one cache, there are to requirements. 4 | 5 | 1. The changes are committed to the database. 6 | 2. All other cahce states must be invalidated and they should reload the states from the database. 7 | 8 | 9 | 10 | The current design in FIgure 1 cannot meet the second requirement. Some important components are missing. Consider to apply architectural pattern and tactic to the design that can meet the second requirement, and complete the following questions. 11 | 12 | 1. Identify extra components that is necessary to meet second requirement. List each component name and it major functionalities. 13 | 2. Draw Sequence diagram to illustrate the communication between your devised components and original components in Figure1. 14 | 3. Assume that servers are heterogenous, and the protocals to access caches on different servers vary. For example, Server 1 support java RMI invocations to cache 1, Server 2 supports http JSP request to cache2, and server 3 supports SOAP requests to cache 3. It is further assumed that the cache interfaces are not consistent to each due ti the evolution of the system development and legacy problems. Explain how the concept if connectors or web services can be applied to provide a generic invocation to caches. You can choose either connector or web services for discussion. 15 | 16 | 17 | 18 | ![](../resource/img.jpg) 19 | 20 | -------------------------------------------------------------------------------- /Software-Architecture/3.architecture-pattern and QA.md: -------------------------------------------------------------------------------- 1 | #### 一. Overview 2 | 3 | ​ In this assignment, I do a lot of researches about architecture patterns, quality attributes and tactics as well as the relationship among them. It takes me **four days** to finish this work. 4 | 5 | #### 二. Avilibility 6 | 7 | ##### 1. Relation between patterns and tatics 8 | 9 | ​ During my research, I found that patterns may use tatics in many **different ways**. In this table, I discuss two relationships. ✘ means the tactic may improve the pattern, but there are also other tactics used often or most real world implentations do not include the tactic. ✔︎ means most the tactic is very helpful to the pattern and also involved in **most** real world implentations. 10 | 11 | ![](/Users/law/Documents/软件体系结构/avilibility.png) 12 | 13 | ##### 2. Patterns' impact on attributes 14 | 15 | 1. **Broker pattern** can improve availability because the broker pattern makes it easy to replace a failed server with another. So if one service fails, there are always another service available. 16 | 2. **Client-server pattern**. If servers are replicated, it is easy to improve availability, which is the benefit to avalibility. But is there is only one server, one point failure would be very common, which add penalty to avalibility. 17 | 3. **Peer-to-peer pattern**. In peer to peer pattern, many nodes perform the same function, if one of them fails,there are always another nodes to replace. So the availability can be improved using peer-to-peer pattern. **However**, if there are not enough nodes, the availability can not be improved. 18 | 4. **Shared-data pattern**. The data store in the shared-data patteren can be a single point of failure. So the availability maybe very poor. Also the avalibility can be improved using many different data stores. 19 | 5. **Multi-tier pattern**. Tiers applied to runtime entities can make it easier to. ensure availability. 20 | 21 | 22 | 23 | ##### 3. Tactics that might not associated with most patterns 24 | 25 | ​ In this part, I mainly discuss **why** these tactics are **not included** in the above table. 26 | 27 | 1. **Software upgrade**. This tactic is not associated with most pattern because upgrading software is not the thing that patterns care about or it is not important to these patterns. 28 | 2. **Shadow**. Shadow is about how to recover from failure, but patterns usually don't care about how to recover. 29 | 3. **Escalating restart**. This is about the stategy to restart system, patterns usually don't have to concern with how to restart. 30 | 4. **Removal from service**. This strategy is more about a decision which decide part of the system not to work to prevent failure. Patterns usually don't make these decisions. 31 | 5. **Predictive model**. This is more like a concrete algorithm, and patterns usually do not predict, at least the patterns above. 32 | 33 | #### 三. Interoperability 34 | 35 | ##### 1.Relation between patterns and tatics 36 | 37 | ![](/Users/law/Documents/软件体系结构/Interoperability.png) 38 | 39 | ##### 2. Patterns' impact on attributes 40 | 41 | 1. **Broker pattern**. The broker pattern makes it easy to the customers and providers. So it improves the interoperablity a lot. 42 | 2. **Service-Oriented Architecture pattern**. The main bebefit and the major driver of SOA is interoperability. Because service providers and service consumers may run on different platforms, wittern in different languages and still work fine. 43 | 44 | ##### 3. Tactics that might not associated with most patterns 45 | 46 | All the tactics mentioned in the book are applied in some of the patterns. 47 | 48 | #### 四. performance 49 | 50 | ##### 1.Relation between patterns and tatics 51 | 52 | ![](/Users/law/Documents/软件体系结构/performance.png) 53 | 54 | #####2. Patterns' impact on attributes 55 | 56 | 1. **Broker pattern**. The broker can help find the providers that are not that busy and this improve the performance to some extent. And broker is an extra layer and certainly add lantency to the excution. 57 | 2. **Pipe and Filter patter**. Filters are independent to each other and can be excuted in parallelism, and this improves performance. 58 | 3. **Client-server pattern**. The server can be the bottleneck of performance and replicate servers can improve performance. 59 | 4. **Peer-to-peer pattern**. There are always more than one nodes perform the same function which reduces the time of hanling and thus improve the performance. 60 | 5. **map-reduce pattern**. Data are mapped into many independent parts and thus are be reduced concurrently, which improves performance. 61 | 6. **Multi-tier pattern**. Tiers applied to runtime entities can make it easier to improve performance of certain framework. 62 | 7. **layered pattern**. Laying always add a performance penalty to a system. If a call is made to a function in the top-most layer, this may have to traverse many lower layers before being executed by the hardware. 63 | 8. **Service-Oriented Architecture pattern**. Like broker pattern, the middle part of the pattern can add lantency to a system, and that is a performance penalty. 64 | 9. **Publish-subscrib pattern pattern**. There is miiddle part of the pattern adding lantency between publisher and subscriber which is a performance penalty. 65 | 66 | ##### 3. Tactics that might not associated with most patterns 67 | 68 | ​ In this part, I mainly discuss **why** these tactics are **not included** in the above table. 69 | 70 | 1. **Manage sampling rate** This is more about a decision made by just quality attributes and not determined by any patterns. We decide sampling rate according to the real world constraints. 71 | 2. **Limit event response**. This is a common decision made by many systems and it is not just determined by any patterns. 72 | 3. **Prioritize events**. Nearly all the systems would take some algorithms to determine the most prioritized events which we can not say certain pattern apply this tatic. 73 | 4. **Reduce overhead**. This is a common problem of many patterns. Some paterns can apply this tactic, but not the patterns we list before. 74 | 5. **Bound execution times**. This is a common scenese to any pattern, so we cannot say this tactic is applied in any patterns. 75 | 6. **Bound queue sizes**. This a common methods used in many applications, but it does not belong to a certain pattern. 76 | 77 | #### 五. Security 78 | 79 | ##### 1. Relation between patterns and tatics 80 | 81 | ![](/Users/law/Documents/软件体系结构/security.png) 82 | 83 | ##### 2. Patterns' impact on attributes 84 | 85 | 1. **Multi-tier pattern**. Tiers applied to runtime entities can make it easier to improve security of certain part of the system. 86 | 2. **Broker pattern**. The broker is easy to attack and that is very dangerous, so the broker add a security penalty to the system. 87 | 3. **client-server-pattern**. If the server is attacked, many important data will lost, which add a security penalty to the system. 88 | 4. **Peer-to-Peer**. We a put different important data to differnent nodes in peer-to-peer pattern, so it becomes easy to achieve security. 89 | 5. **Service-Oriented Architecture**. The servcie is out of the system, so the security of the system is determined by other system, which adds a security penalty to the system. 90 | 6. **Shared-data**. If the data stores of the pattern is attacked, all the important data will lost, which add a security penalty to the system. 91 | 92 | ##### 3. Tactics that might not associated with most patterns 93 | 94 | ​ In this part, I mainly discuss **why** these tactics are **not included** in the above table. 95 | 96 | 1. **Detect message delay**. This is a very useful tactic, but none of the patterns above id about this parts of the system. 97 | 2. **Revoke access**. This is more about a decision according to the environment, which is not something that a pattern can decide. 98 | 3. **Lock computer**. This is a very specific solution and is a common scense to everyone, and a pattern cannot describ this. 99 | 4. **Inform actors**. Almost every applications in real world use this tactic, and this can not just belong to some certain patterns. 100 | 101 | #### 六. Testability 102 | 103 | ##### 1. Relation between patterns and tatics 104 | 105 | ![](/Users/law/Documents/软件体系结构/Testability.png) 106 | 107 | ##### 2. Patterns' impact on attributes 108 | 109 | 1. **Layered pattern**. Layed pattern makes sure that differnet functions are in different layers, so complexity of the system is very low. And that makes it very easy to test. 110 | 2. **MVC pattern**. MVC pattern seperate the views, controllers and models and that also reduce the complexity of teh system, which makes it very easy to test. 111 | 3. **Pipe-and-Filter pattern**. FIlters are independent in this pattern, so filters can be tested seperately, which makes it easy to test. 112 | 4. **Publish-Subscribe pattern**. Publishers and subscribers are nearly independent, so we can also test them seperately, which makes it very easy to test. 113 | 5. **Map-Reduce pattern**. Map parts and reduce parts of the system can be tested seperately, which makes it very easy to test. 114 | 6. **Service-Oriented Architecture pattern**. The system has to communicate to many other systems in this pattern, so it can be hard to test, which add a testability penalty to the system. 115 | 7. **Broker pattern pattern**. The broker part of the system can be very complex and very hard to test, which add a testability penalty to the system. 116 | 8. **Peer-to-Peer pattern**. The scale of the system can be very large and there may be too many nodes, which makes it very hard to test. 117 | 118 | ##### 3. Tactics that might not associated with most patterns 119 | 120 | ​ In this part, I mainly discuss **why** these tactics are **not included** in the above table. 121 | 122 | 1. **Specialized interfaces**. This is a tactic in the coding level which is not what any architecture patterns can decide. 123 | 2. **Record/playback** . This is not the things in the architecture level, and not belongs to any specific architecture patterns. 124 | 3. **Localize state storage**. This is a tactic in the coding level which is not what any architecture pattern can decide. 125 | 4. **Sandbox** This a common test techique, and the above architecture patterns do not include this test technique. 126 | 5. **Executable assertions**. This is coding level tactic, and architecture patterns do not decide how to code. 127 | 128 | #### 七. Usability 129 | 130 | ##### 1. Relation between patterns and tatics 131 | 132 | ![](/Users/law/Documents/软件体系结构/usability.png) 133 | 134 | ##### 2. Patterns' impact on attributes 135 | 136 | 1. **Pipe and Filter pattern**. This pattern maybe very good to the undo tactic, and thus improve the usability. 137 | 2. **MVC pattern**. MVC pattern can makes it easy to make interactive systems, which improves the usability. 138 | 139 | ##### 3. Tactics that might not associated with most patterns 140 | 141 | ​ In this part, I mainly discuss **why** these tactics are **not included** in the above table. 142 | 143 | 1. **Cancel**. It is more like a specific functional requirement, and can be implemented in may different ways, and is cerntainly not involed in any patterns. 144 | 2. **Pause/resume**. Patterns concern about how to design, not function requirements, so this may not be involed in any patterns. 145 | 3. **Maintain task model**. This is a algorithm used in system, but none of the patterns above use this tactic. 146 | 4. **Maintain user model** This can be seen ad an algorithm or a decision made by function requirements, and is not involed in the patterns above. 147 | 5. **Maintain system model** It is more like a specific functional requirement, and can be implemented in may different ways, and is cerntainly not involed in any patterns. -------------------------------------------------------------------------------- /Software-Architecture/3.architecture-pattern.md: -------------------------------------------------------------------------------- 1 | # 软件架构模式 2 | 3 | 4 | 5 | ## 一. 什么是 架构模式 6 | 7 | **架构模式** 是一系列 **不断** 在实践中使用的 **设计决策** 的集合,并且是由一些便于进行 **重用** 的特性进行描述的架构。 8 | 9 | 总结来说就是人们在实际的软件开发中发现的非常好用并且经常使用的设计决策和方法, 架构模式 是被 **发现** 的,不是被 **发明** 的。 在新的开发情景下,总会有新的 **架构模式** 出现。 10 | 11 | **《Software Architecture in Practice》** 中定义的 描述 **架构模式** 的 **三元组**: **情景**,**问题**, **解决方案** 12 | 13 | - **情景:** 一个可以 **复现** 的, **普遍**的 现实中问题发生的环境。 14 | - **问题:** 要说明问题要求的 **质量属性** , 和遇到的 **困难**。 15 | - **解决方案:** 主要包括 **一系列的元素种类**, 一系列的 **连接件**或者**交互机制**, 组件之间的 **布局**, 上述的一些 **限制** 。 16 | 17 | 18 | 19 | ## 三种高层模式 20 | 21 | 22 | 23 | 24 | 25 | ## 二. 分层模式 26 | 27 | - **情景:** 开发 **大型复杂系统** 需要将系统中的模块分离进行 **独立开发** 28 | 29 | - **问题:** 软件需要以一种模块之间 **关联和依赖最小** 的方式进行模块划分,以支持 **可移植性**, **可修改性** 和 进行**复用**。 30 | 31 | - **解决方案:** 把整个软件划分成 层,每一层都提供一种有内聚性的服务。 层和层之间的相互调用是单向的, 不允许 **跨层调用** , 也不允许 **下层调用上层**。 32 | 33 | 34 | 35 | ​ 分层 会增加 **成本** 和 **复杂度** , 并且会对系统造成 **性能损失**,因为即使是一个上层的一个非常简单的功能调用也要经过层层的调用才能完成。 36 | 37 | ​ 38 | 39 | ​ 分层模式非常普遍, 这里也就不 太详细去描述了, 最常见的分层就是 **UI**, **业务逻辑** , **数据库** 的分层方式。 40 | 41 | ## 三. Broker 模式 42 | 43 | - **情景: ** 很多系统是由分散在 **不同服务器** 上的服务构建而成的, 实现这样的系统的复杂程度在于必须要去考虑 **系统如何和其他的系统进行交互**, 并且其他的系统的**可用性**会对我们的系统 **直接产生影响**。 (隐含了一些**面向服务** 的思想) 44 | - **问题:** 如何让服务的使用者不需要知道服务提供者的细节,并且可以灵活的建立服务提供者和服务服务使用者的绑定关系。 45 | - **解决方案:** 通过一个 **Broker** 的角色把服务的使用者和服务的提供者进行分离。 用户向 中间人发起请求, 中间人根据请求找到最合适的服务提供者。 46 | 47 | **Broker 模式是一种典型的分布式模式** 48 | 49 | 优点: 50 | 51 | 1. 当一个服务器不可用的时候, Broker 可以灵活的选择其他相似的服务。 52 | 2. 如果有新的服务器加入,不需要对用户进行更改。 53 | 3. Broker 可以灵活选择最快速的服务器,提升了系统的性能。 54 | 55 | 56 | 57 | 缺点: 58 | 59 | 1. 增加了设计的复杂度, 必须去设计更多的代理人和一些消息协议。 60 | 2. 多增加了一层,会增加通讯延迟,对性能有影响。 61 | 3. 情景复杂, 错误情景很难复现,导致可测试性不高。 62 | 4. Broker 容易成为被攻击的对象, 并且 Broker 容易单点失效。 63 | 5. Broker 也可能成为性能的瓶颈所在。 64 | 6. 用户和服务者的隔离会 影响 本来 可以对 服务提供者 做的特定的优化, 从而间接的影响了性能。 65 | 66 | 67 | 68 | **Broker 模式的示意图如下图所示** 69 | 70 | 包括 client, client-proxy, broker, bridge, server, server-proxy 6个部分。 71 | 72 | 其中 client-proxy 和 server-proxy 是对服务的封装,使得调用远程方法就如同调用本地方法一样, 如同 **RMI** 73 | 74 | Bridge 用来连接 各个 Broker, 当系统的实现特别复杂的时候,可能会需要这个角色。 75 | 76 | drawing 77 | 78 | 79 | 80 | **Broker 模式在实际中的应用:** 81 | 82 | 1. **消息队列(MQ)** 83 | 84 | **消息队列** 是的主要应用场景是将一些比较耗时并且不需要同步的结果 放入队列中,等待调用相关的服务。 所以 消息队列 其实就承担了 Broker 的角色。 85 | 86 | 下图就简单的说明了消息队列中的 Broker 模式。 87 | 88 | drawing 89 | 90 | 2. **EJB(Enterprise JavaBean )** 91 | 92 | **EJB** 是 JavaEE 中面向服务的体系架构的解决方案,可以将功能封装在服务器端,以服务的形式对外发布, 客户端可以在无须知道具体的实现细节的情况下调用远程方法。 EJB 更像是提供了一种接口的规范,比如java 中的 **RMI** 和**JDNI** 进行相关服务的调用。 93 | 94 | 个人理解, EJB 承担了各种复杂的业务的定义和交流,调用等,所以也可以被看作是一个 **Broker** ? 95 | 96 | 97 | 98 | 99 | 100 | ## MVC 模式 101 | 102 | **情景:** 交互频繁的 用户界面 部分是软件中变更最频繁的部分, 所以让用户界面部分的变化不影响实际的系统数据的变化十分重要。 还要能够支持使用不同的方式展示相同的数据,数据变化的时候展示也能够进行实时更新。 103 | 104 | **问题:** 如何让用户界面部分和系统的实际功能部分完全分离, 如何能够使得数据发生变化的时候多套用户界面全都发生改变。 105 | 106 | **解决方案:** 107 | 108 | MVC 模式, 设置了3种组件 109 | 110 | - Model: 存储系统中的数据 111 | - View: 展示系统中的数据并且和用户进行交互 112 | - Controller: 在Model 和 View 中间,再负责在系统的状态改变的时候进行通知。 113 | 114 | **一些小问题:** 115 | 116 | 1. 对与相对简单的界面系统,实现成本可能相对较高。 117 | 2. 一些用户界面库和 MVC 模式之间可能不是完全兼容。 118 | 119 | MVC 组件之间的通讯一般是使用事件或者回调的方式进行的。 120 | 121 | MVC 组件时间的耦合度非常底,所以非常方便进行平行的测试,并且一个组件的改变对其他组件的影响不会非常大。 122 | 123 | 下图就是 MVC 模式的一般结构。 124 | 125 | drawing 126 | 127 | 下面是一个简单的计数器系统的 MVC 实现方式。 128 | 129 | 首先是 Model 部分,counter 变量就是系统的数据。 Model 继承了 Observable, 也就是 MVC 中隐含着 观察者模式, notifyObservers 方法通知相应的观察者。 130 | 131 | ```java 132 | public class Model extends java.util.Observable { 133 | 134 | private int counter; //primitive, automatically initialised to 0 135 | 136 | public Model(){ 137 | 138 | System.out.println("Model()"); 139 | 140 | } 141 | 142 | public void setValue(int value) { 143 | this.counter = value; 144 | System.out.println("Model init: counter = " + counter); 145 | setChanged(); 146 | notifyObservers(counter); 147 | } 148 | 149 | public void incrementValue() { 150 | ++counter; 151 | System.out.println("Model : counter = " + counter); 152 | setChanged(); 153 | notifyObservers(counter); 154 | } 155 | } 156 | ``` 157 | 158 | 然后是 View 部分, update 方法作为观察着模式的更新方法。 159 | 160 | ```java 161 | import java.awt.Button; 162 | import java.awt.Panel; 163 | import java.awt.Frame; 164 | import java.awt.TextField; 165 | import java.awt.Label; 166 | import java.awt.event.WindowEvent; 167 | import java.awt.event.WindowAdapter; 168 | import java.lang.Integer; 169 | import java.util.Observable; 170 | 171 | class View implements java.util.Observer { 172 | 173 | private TextField myTextField; 174 | private Button button; 175 | View() { 176 | System.out.println("View()"); 177 | Frame frame = new Frame("simple MVC"); 178 | frame.add("North", new Label("counter")); 179 | myTextField = new TextField(); 180 | frame.add("Center", myTextField); 181 | Panel panel = new Panel(); 182 | button = new Button("PressMe"); 183 | panel.add(button); 184 | frame.add("South", panel); 185 | frame.addWindowListener(new CloseListener()); 186 | frame.setSize(200,100); 187 | frame.setLocation(100,100); 188 | frame.setVisible(true); 189 | } 190 | public void update(Observable obs, Object obj) { 191 | myTextField.setText("" + ((Integer)obj).intValue()); 192 | } 193 | public void setValue(int v){ 194 | myTextField.setText("" + v); 195 | } 196 | 197 | public void addController(Controller controller){ 198 | System.out.println("View : adding controller"); 199 | button.addActionListener(controller); 200 | } 201 | 202 | public static class CloseListener extends WindowAdapter { 203 | public void windowClosing(WindowEvent e) { 204 | e.getWindow().setVisible(false); 205 | System.exit(0); 206 | } 207 | } 208 | 209 | } 210 | ``` 211 | 212 | 最后是 Controller 部分: 213 | 214 | ```java 215 | class Controller implements java.awt.event.ActionListener { 216 | 217 | Model model; 218 | View view; 219 | 220 | Controller() { 221 | System.out.println ("Controller()"); 222 | } 223 | 224 | public void actionPerformed(java.awt.event.ActionEvent e){ 225 | System.out.println("Controller: acting on Model"); 226 | model.incrementValue(); 227 | } 228 | 229 | public void addModel(Model m){ 230 | System.out.println("Controller: adding model"); 231 | this.model = m; 232 | } 233 | 234 | public void addView(View v){ 235 | System.out.println("Controller: adding view"); 236 | this.view = v; 237 | } 238 | 239 | public void initModel(int x){ 240 | model.setValue(x); 241 | } 242 | 243 | } 244 | ``` 245 | 246 | 驱动代码, 明确各个部分之间的关系: 247 | 248 | ```java 249 | public class RunMVC { 250 | private int start_value = 10; 251 | 252 | public RunMVC() { 253 | Model myModel = new Model(); 254 | View myView = new View(); 255 | myModel.addObserver(myView); 256 | Controller myController = new Controller(); 257 | myController.addModel(myModel); 258 | myController.addView(myView); 259 | myController.initModel(start_value); 260 | myView.addController(myController); 261 | } 262 | } 263 | ``` 264 | 265 | 266 | 267 | 从上面可以看到 MVC 模式也不同于简单的分层, Model 和 View 之间是存在耦合关系的, 但是这种耦合关系被观察者模式给最大限度的降低了。 268 | 269 | **MVC 在实际的项目中的运用** 270 | 271 | 1. java 的 Swing 库就是 MVC 模式的最典型的应用。 272 | 2. ASP.NET 采用了 MVC 273 | 3. Nokia's Qt framework 274 | 275 | ## Pipe-and-Filter 模式 276 | 277 | **情景:** 很多系统要对不同数据对象进行数据流转换,有时候这些转换在实际中非常普遍,所以由必要把这些抽象成独立的,可以重用的组件。 278 | **问题:** 很多系统需要被分成可以重用的,低耦合的组件。 这些组件要求可以非常灵活的和其他的组件进行组合, 并且很容易进行重用。 组件之间相互独立也让组件可以进行并行的计算。 279 | **解决方案:** 数据之间交互的方式是流式数据连续不断的转换, 数据到达 filter 的输入端口,转换之后 从 filter 的输出端口 经过 一个 Pipe 到达下一个 Filter。 280 | 281 | **缺点:** 282 | 283 | 1. 不利于实时性要求比较强的系统(不允许回调,并且处理的步骤比较长) 284 | 2. 长期进行计算需要加一些保存点,否则单点失效容易造成整个系统的失效 285 | 286 | ## Client-Server 模式 287 | 288 | **情景:** 大量的分布用户希望去共享一些资源或者服务,并且能够对服务的访问和质量做出一些控制。 289 | **问题:** 通过管理一些分享的资源或者服务,可以提升可修改性和重用性,因为我们可以把这些资源或者服务集中起来进行使用。 290 | **解决方案:** 两个基本组件, client 和 server, 最基本的连接方式是通过一些 请求/回复 协议驱动的数据连接件。 291 | 292 | **缺点:** 293 | 294 | 1. server 会成为性能的瓶颈, 容易单点失效导致整个系统失效。 295 | 2. 把功能做在 client 还是 server 这样的决定一旦做出就不太容易进行修改。 296 | 297 | **常见的模式应用:** 298 | 299 | 1. 信息系统, client 是用户界面系统, server 是数据库管理系统。 300 | 2. Web 应用, 浏览器是 client 301 | 302 | 对 server 进行扩增就是分布式应用,可以有效的提升可用性。 303 | 304 | ## Peer-to-Peer 模式 305 | 306 | **情景:** 在通讯和提供资源对角度上同等重要的 分布式计算实体,需要合作去给不同地区的用户提供服务。 307 | **问题:** 平等的计算实体如何在保证高可用性和高扩展性的情况下彼此之间通过共同的协议进行交流以提供他们的服务。 308 | **解决方案:** 每个组件直接和其余的组件进行交互,所有的组件都是平等的,没有对于整个系统有决定性作用的组件。 通讯方式也是传统上的请求回复方式 但不是 client-server 种的非对称方式. 每个 peer 都同时是 client 和 server。 所有的 peer 使用相同的服务,并且使用相同的协议。 309 | 310 | 一个 peer-to-peer 架构一般会有若干有索引和搜寻能力的超级节点,能够让一个正常节点找到其他更多的节点。 311 | 312 | 由于多个Peer 可以提供相同的服务,所以在一个 Peer 不可用的时候,可以由其他的 peer 进行代替,这样就很大程度上的提升了系统的可用性。 313 | 314 | Peer-to-Peer 也会使得分配在每一个peer上的性能压力变小,从而从整体上提升系统的性能。 315 | 316 | **缺点:** 317 | 318 | 1. 管理安全性, 数据的一致性, 数据和服务的可用性都会非常的复杂。 319 | 2. 系统的质量属性提高保证,只能通过概率的方式进行预测。 320 | 321 | 322 | 323 | 324 | 325 | ## Service-Oriented Architecture 模式 326 | 327 | **情景:** 大量的服务被服务生产者提供,被用户使用。 服务的用户需要在不需要知道这些服务的实现细节的情况下去使用这些服务。 328 | 329 | **问题:** 我怎么样提高 在不同平台上, 使用不同的编程语言制作的, 由不同的组织提供, 分布在整个互联网上的组件的互操作性。 如何去使用不同的服务并且组合起来还要有不错的性能,安全性,和可用性。 330 | 331 | **解决方案:** SOA pattern 描述了一系列使用和提供服务的组件。 每个组件有描述其他组件提供的服务的描述的接口。 Service-level aggrement 可以来保证服务的质量。 一个组件通过请求不同的服务来完成功能。 332 | 333 | 一个SOA 应用必须还要使用一些提高基础服务的中间件组件。 334 | 335 | - 一个服务的调用必须由一个 ESB(enterprise service bus) 来进行中间调解。 一个ESB在服务的提供者和服务的使用者之间传递信息。 并且一个 ESB 可以把信息从一种语言或者协议变成另一种,进行安全检查,管理事务。 使用ESB 促进了互操作性。安全性和可修改性。 但是同时也增加了通讯的开销,对性能有一定的影响。 当ESB失效的时候,服务的使用者和消费者也可以进行点对点的通讯。 336 | - 可以使用服务注册表(service refistry)来提升服务提供者的独立性。 注册表是一个可以允许服务在运行时被注册的基本组件。 这样可以在运行时发现服务,有效的提升了系统的可修改性,一个服务注册表甚至可以允许同一时间同一个服务可以有不同的版本。 337 | - Orchestration server 管理在一个SOA系统中不同的服务消费者和提供者之间的交互。 在特定事件发生的时候会执行脚本。 对和外部的组件或系统交互的业务流程或者工作流定义的非常好的系统可以在使用 Orchestration server 的时候取得非常好的互操作性,和可靠性。 很多商业上可用的 Orchestration server 支持很多不同的工作流和业务过程语言模型。 338 | 339 | 在SOA系统中一些通用的连接组件 340 | 341 | - SOAP: web服务通讯的标准协议,通过HTTP协议进行交换XML格式的信息。 342 | - Representational State Transfer(Rest): 使用标准的 HTTP 协议, 通过使用基本的HTTP 方法(POST, GET, PUT, DELETE) 来进行请求服务。 343 | - 异步消息通讯, 一种发完消息就不管了的方法。 参与不必等待对方收到信息的确认,基础的设施已经默认了信息已经成功ing进行了传输。 消息通讯的连接组件可以是点对点的,也可以是发布,订阅模式。 344 | 345 | 实际中的SOA环境可能采用多种混合的连接方式。 一些 消息队列(MQ) 实际上是提供了一些异步的消息通讯。 346 | 347 | **缺点:** 348 | 349 | 1. 设计和实现非常复杂 350 | 2. 由中间件造成的性能延迟,和过于依赖其他服务导致的性能难以保证。 351 | 3. 和Broker模式相同的缺点, 因为设计的理念和目标和Broker模式是类似的。 352 | 353 | **优点** 354 | 355 | 1. 互操作性非常强, 服务提供者和使用者的差异性可能非常大。 356 | 357 | 下面是一个使用了SOA的系统: Adventure Builder. 358 | 359 | 这个系统允许用户通过选择各种活动或者交通方式来组成一次旅行。 这个系统和很多外部的服务提供者进行进行交互来完成功能, 比如要和银行系统,订单系统,交通系统,活动系统进行通信和使用服务。 使用SOAP的方式可以方便的完成这样的互操作通信。 360 | 361 | drawing 362 | 363 | ## Publish-Subscribe 模式 364 | 365 | **情景:** 有很多相互独立的数据的生产者和使用者必须进行交互。 数据的生产者和使用者和交互的数据都是不确定的。 366 | 367 | **问题:** 如何确定一套完整的能够支持数据的生产者和使用者进行相互交互并且生产者和使用者之间不需要彼此之间相互了解长度机制。 368 | 369 | **解决方案:** 在publish-subscrib 模式中,组件之间通过事件进行交互。 组件必须订阅一系列的事件,然后由 publish-subscrib 的运行时基础设施 来确保发布的事件被传递到所有的订阅者。 主要的连接方式就是事件总线(event bus)。 发布者发布事件到总线上,总线负责把事件给订阅者。 370 | 371 | **缺点:** 372 | 373 | 1. 由不确定的事件延迟,适合异步系统,实时性不高, 并且很难有十分复杂的交互。 374 | 375 | Publish-Subscrib 的计算模型最好可以被想象成独立的进程或者物体,和在环境中产生的事件进行交互,最终和其他的组件进行交互。 376 | 377 | 下面是一个Public-Subcsrib 模式的例子。 378 | 379 | drawing 380 | 381 | 一些实际的应用还有 382 | 383 | - 图形用户界面, 用户的低层次输入被认为是事件传给事件处理器。 384 | - MVC应用: 其中的观察者模式就是非常好的例子 385 | - ERP系统: 集成了很多组件,每个组件只接受一部分事件。 386 | - 扩展编程环境,工具之间通过事件进行交流。 387 | - 邮件系统: 典型的应用,用户只收到自己注册的事件。 388 | - 社交网络, 一个朋友的动态更新了自己会收到通知。 389 | 390 | Publish-subscrib 模式实际中有好多种形式: 391 | 392 | 1. 基于列表的发布和订阅,每个发布者维护一个订阅列表。 可修改性不高,性能还行。 393 | 2. 基于广播的发布和订阅。 发布者不知道发给谁,采用广播的方式,订阅者判断是否接受。 可能有潜在的不高效的问题。 394 | 3. 基于内容的发布和订阅,可以说是基于主题的。 通过内容的标签进行判断。 395 | 396 | 在实际中 Publish-subscrib 模式会由一些 面向信息的中间件组成,中间件可以被看成是一个 Broker。 中间件还要定位,存储和转换数据。 所以这个模式其实和broker模式由很多相似之处。 397 | 398 | ## Shared-Data 模式 399 | 400 | **情景:** 很多个系统组件需要共享和操作大规模的数据, 这些数据不属于任何一个系统 401 | 402 | **问题:** 系统是怎样存储操作可以被大规模访问的数据的。 403 | 404 | **解决方案:** 在 Shared-data 模式中, 数据交换主要是 数据访问器 和 至少有一个的 共享数据仓库之间的。 通用计算模型是数据访问器从数据仓库中拿到数据并且向数据仓库中写入一条或者更多的数据。 在纯的 Shared-data 系统中, 数据访问器之间只能通过数据仓库进行交流。 实际应用中可能会打破这个准则。 405 | 406 | **缺点:** 407 | 408 | 1. 数据仓库可能会成为性能瓶颈 409 | 2. 可能会因为单点故障导致整个系统失效 410 | 3. 数据访问器和数据仓库的耦合可能太紧密了 411 | 412 | **优点** 413 | 414 | 1. 将数据的提供和使用接耦,这一点对可修改性有积极的影响 415 | 416 | 下面是一个 Shared-data 的例子,这个例子中有一个中心存储的数据仓库,数据的访问器有各种个样的客户端。 417 | drawing 418 | 419 | ## Map-Reduce 模式 420 | 421 | **情景:** 业务中需要去快速的去处理和分析超大规模的数据。 并且这样的程序应该容易书写,运行起来非常高效,对硬件失效也能有非常好的应对。 422 | 423 | **问题:** 对于大多数有超大规模数据的系统,对数据进行排序并且分析分类好的数据是非常有效的。 Map-reduce pattern 就是要使用一个分布式的并行排序算法高效的解决这个问题并且提供一个让程序员非常容易对数据进行分析的方法。 424 | 425 | **解决方案:** Map-reduce 模式有三部分, 第一部分是一个能够在大规模并行计算的环境下灵活的将软件分派到硬件节点上的定制基础设施并且需要的时候能够处理这些数据的排序。 硬件节点可能是独立的处理器也可能是多核处理器。 第二个第三个部分是两个非常重要的函数, map 和 reduce。 426 | 427 | map函数接受一个 key 和一个 数据集作为输入,map函数的目的是对数据集进行过滤和排序。 所有的复杂分析都要在reduce函数中完成, 428 | 429 | 一个数据是否会在之后的进一步处理中呗用到要看map函数。 第二个key 对于map函数也十分的重要, 这是用于排序的key,map 函数的输出就是。 430 | 431 | 排序是由map 函数和 基础的结构联合执行的。 得到的每条数据都由 key2 进行哈希进入一个硬盘分区中, 基础结构保留了key2的索引文件,这样使得硬盘里的数据可以被重新组合成 key2 的顺序。 432 | 433 | map部分的性能提升可以通过增加map实例的数量达到,每一个都处理不同硬盘分区中的数据。 434 | 435 | reduce 函数做一些程序中规定的(业务规定)的分析,然后产生结果。 结果集几乎总是比输入的集合要小,所以这个过程也叫做reduce. 436 | 437 | drawing 438 | 439 | 下面是不适合使用过 Map-reduce 模式的情况: 440 | 441 | - 如果你没有一个很大数据集,完全没有必要使用map-reduce. 442 | - 如果你不能把你的数据分成很多更小的子集,那么map-reduce的优势就没有了。 443 | - 如果你由需要很多 reduce 函数的操作,那么掌控起来会非常复杂。 444 | 445 | Map-reduce 的商业实现 提供了一套能够把函数实体映射到硬件上, 从硬件的错误中恢复, 还有一些比较好的排序工具。 446 | 447 | ## Multi-tier 模式 448 | 449 | **情景:** 在一个分布式部署函数中,通常会有把系统的基础结构放到不同的子集中的需要。 可能由于操作上的或者商业上的原因。 (不同基础的组件可能属于不同的公司) 450 | 451 | **问题:** 我们怎么才能将系统分解成更多的计算独立的计算结构, 一系列软件和硬件的集合, 由一些交流媒介相互联系。 这样做的目的是进行特定的服务器环境的优化来满足一些操作需求和资源的使用。 452 | 453 | **解决方案:** 系统的计算结构是由一些列的计算组件构成的, 每个被成为一个 tier, 把组件的集合变成一个 tier 由很多不同的标准。 454 | 455 | tier 可以被映射到很多运行时组件中,及时在事件中最经常被用到的是 client-server 的模式中。 Tier 引入了拓扑上的规定哪些组件可以和某个组件交流。 连接件可能只会出现在同一个 tier 或者在相邻的 tier 中。 Multi-Tier 模式在很多 java EE 和 Microsoft .Net 应用中会被发现。 456 | 457 | **缺点:** 458 | 459 | 1. 成本很大并且非常复杂, 对与小的系统,这样并不划算。 460 | 461 | Tier 不是组件,也不是组件的逻辑群组。 也不要把Tier 和 layer 混淆。 layer 是一种实现中的单元和模块, 而tier 是一种运行中的实体。 462 | 463 | **优点:** 464 | 465 | 1. 很容易保障安全行,性能和可用性 466 | 2. 也提高了系统的可修改性 467 | 468 | 下面是一个 multi-tier 架构的实例, 这是一个用 javaEE 技术实现的网站系统。 469 | drawing 470 | 471 | Multi-tier Pattern 472 | 473 | The multi-tier pattern is a C&C pattern or an allocation pattern, depending on the criteria used to define the tiers. Tiers can be created to group components of similar functionality, in which case it is a C&C pattern. However, in many, if not most, cases tiers are defined with an eye toward the computing environment on which the software will run: A client tier in an enterprise system will not be running on the computer that hosts the database. That makes it an allocation pattern, mapping software elements—perhaps produced by applying C&C patterns—to computing elements. Because of that reason, we have chosen to list it as an allocation pattern. 474 | 475 | The use of tiers may be applied to any collection (or pattern) of runtime components, although in practice it is most often used in the context of cli- ent-server patterns. Tiers induce topological constraints that restrict which com- ponents may communicate with other components. Specifically, connectors may exist only between components in the same tier or residing in adjacent tiers. The multi-tier pattern found in many Java EE and Microsoft .NET applications is an example of organization in tiers derived from the client-server pattern. 476 | 477 | Additionally, tiers may constrain the *kinds* of communication that can take place across adjacent tiers. For example, some tiered patterns require call-return communication in one direction but event-based notification in the other. 478 | 479 | The main weakness with the multi-tier architecture is its cost and complex- ity. For simple systems, the benefits of the multi-tier architecture may not justify its up-front and ongoing costs, in terms of hardware, software, and design and implementation complexity. 480 | 481 | Tiers are not components, but rather logical groupings of components. Also, don’t confuse tiers with layers! Layering is a pattern of modules (a unit of imple- mentation), while tiers applies only to runtime entities. 482 | 483 | Table 13.11 summarizes the solution part of the multi-tier pattern. 484 | 485 | Tiers make it easier to ensure security, and to optimize performance and availability in specialized ways. They also enhance the modifiability of the sys- tem, as the computationally independent subgroups need to agree on protocols for interaction, thus reducing their coupling. 486 | 487 | Figure 13.15 uses an informal notation to describe the multi-tier architecture of the Consumer Website Java EE application. This application is part of the Ad- venture Builder system. Many component-and-connector types are specific to the supporting platform, which is Java EE in this case. 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | ### Pattern 和 Tactic 498 | 499 | 1. **Patterns comprise tactics** 500 | 501 | As we said in the introduction to this chapter, tactics are the “building blocks” of design from which architectural patterns are created. Tactics are atoms and patterns are molecules. Most patterns consist of (are constructed from) several different tactics, and although these tactics might all serve a common purpose— such as promoting modifiability, for example—they are often chosen to promote *different* quality attributes. For example, a tactic might be chosen that makes an availability pattern more secure, or that mitigates the performance impact of a modifiability pattern. 502 | 503 | Consider the example of the layered pattern, the most common pattern in all of software architecture (virtually all nontrivial systems employ layering). The layered pattern can be seen as the amalgam of several tactics—increase semantic coherence, abstract common services, encapsulate, restrict communication paths, and use an intermediary. For example: 504 | 505 | - *Increase semantic coherence*. The goal of ensuring that a layer’s respon- sibilities all work together without excessive reliance on other layers 506 | is achieved by choosing responsibilities that have semantic coherence. Doing so binds responsibilities that are likely to be affected by a change. For example, responsibilities that deal with hardware should be allocated to a hardware layer and not to an application layer; a hardware respon- sibility typically does not have semantic coherence with the application responsibilities. 507 | - *Restrict dependencies*. Layers define an ordering and only allow a layer to use the services of its adjacent lower layer. The possible communication paths are reduced to the number of layers minus one. This limitation has a great influence on the dependencies between the layers and makes it much easier to limit the side effects of replacing a layer. 508 | 509 | ​ Without any one of its tactics, the pattern might be ineffective. For example, if the restrict dependencies tactic is not employed, then any function in any layer can call any other function in any other layer, destroying the low coupling that makes the layering pattern effective. If the increase semantic coherence tactic is not employed, then functionality could be randomly sprinkled throughout the layers, destroying the separation of concerns, and hence ease of modification, which is the prime motivation for employing layers in the first place. 510 | 511 | 2. **using tactics to augment Patterns** 512 | 513 | A pattern is described as a solution to a class of problems in a general context. When a pattern is chosen and applied, the context of its application becomes very specific. A documented pattern is therefore underspecified with respect to applying it in a specific situation. 514 | 515 | To make a pattern work in a given architectural context, we need to examine it from two perspectives: 516 | 517 | 1. - The inherent quality attribute tradeoffs that the pattern makes. Patterns exist to achieve certain quality attributes, and we need to compare the ones they promote (and the ones they diminish) with our needs. 518 | - Other quality attributes that the pattern isn’t directly concerned with, but which it nevertheless affects, and which are important in our application. 519 | 520 | To illustrate these concerns in particular, and how to use tactics to augment patterns in general, we’ll use the broker pattern as a starting point. 521 | 522 | The broker pattern is widely used in distributed systems and dates back at least to its critical role in CORBA-based systems. Broker is a crucial component of any large-scale, dynamic, service-oriented architecture. 523 | 524 | Using this pattern, a client requesting some information from a server does not need to know the location or APIs of the server. The client simply contacts the broker (typically through a client-side proxy); this is illustrated in the UML sequence diagram in Figure 13.16. 525 | 526 | 527 | 528 | **Weaknesses of the broker Pattern.** In Section 13.2 we enumerated sev- eral weaknesses of the broker pattern. Here we will examine these weaknesses in more detail. The broker pattern has several weaknesses with respect to certain quality attributes. For example: 529 | 530 | * *Availability*. The broker, if implemented as suggested in Figure 13.6, is a single point of failure. The liveness of servers, the broker, and perhaps even the clients need to be monitored, and repair mechanisms must be provided. 531 | 532 | - *Performance*. The levels of indirection between the client (requesting 533 | the information or service) and the server (providing the information or service) add overhead, and hence add latency. Also, the broker is a potential performance bottleneck if direct communication between the client and server is not desired (for example, for security reasons). 534 | - *Testability*. Brokers are employed in complex multi-process and multi- processor systems. Such systems are typically highly dynamic. Requests and responses are typically asynchronous. All of this makes testing and debugging such systems extremely difficult. But the description of the broker pattern provides no testing functionality, such as testing interfaces, state or activity capture and playback capabilities, and so forth. 535 | 536 | Of these quality attributes, the broker pattern is mainly associated with poor performance (the well-documented price for the loose coupling it brings to systems). It is largely unconcerned with the other quality attributes in this list; they aren’t mentioned in most published descriptions. But as the other bullets 537 | show, they can be unacceptable “collateral damage” that come with the broker’s benefits. 538 | 539 | 540 | 541 | **Improving the broker Pattern with tactics.** How can we use tactics to plug the gaps between the “out of the box” broker pattern and a version of it that will let us meet the requirements of a demanding distributed system? Here are some options: 542 | 543 | - The increase available resources performance tactic would lead to multiple brokers, to help with performance and availability. 544 | 545 | - The maintain multiple copies tactic would allow each of these brokers to share state, to ensure that they respond identically to client requests. 546 | 547 | - Load balancing (an application of the scheduling resources tactic) would ensure that one broker is not overloaded while another one sits idle. 548 | 549 | - Heartbeat, exception detection, or ping/echo would give the replicated brokers a way of notifying clients and notifying each other when one of them is out of service, as a means of detecting faults. 550 | 551 | Of course, each of these tactics brings a tradeoff. Each complicates the de- sign, which will now take longer to implement, be more costly to acquire, and be more costly to maintain. Load balancing introduces indirection that will add latency to each transaction, thus giving back some of the performance it was in- tended to increase. And the load balancer is a single point of failure, so it too must be replicated, further increasing the design cost and complexity. 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | ### SOA 562 | 563 | Service-Oriented Architecture Pattern 564 | 565 | **Context:** A number of services are offered (and described) by service provid- ers and consumed by service consumers. Service consumers need to be able to understand and use these services without any detailed knowledge of their implementation. 566 | 567 | **Problem:** How can we support interoperability of distributed components run- ning on different platforms and written in different implementation languages, provided by different organizations, and distributed across the Internet? How can we locate services and combine (and dynamically recombine) them into meaning- ful coalitions while achieving reasonable performance, security, and availability? 568 | 569 | **Solution:** The service-oriented architecture (SOA) pattern describes a collection of distributed components that provide and/or consume services. In an SOA, *ser- vice provider* components and *service consumer* components can use different implementation languages and platforms. Services are largely standalone: service providers and service consumers are usually deployed independently, and often belong to different systems or even different organizations. Components have in- terfaces that describe the services they request from other components and the services they provide. A service’s quality attributes can be specified and guar- anteed with a service-level agreement (SLA). In some cases, these are legally binding. Components achieve their computation by requesting services from one another. 570 | 571 | 572 | 573 | 574 | 575 | The elements in this pattern include service providers and service consum- ers, which in practice can take different forms, from JavaScript running on a web browser to CICS transactions running on a mainframe. In addition to the service provider and service consumer components, an SOA application may use specialized components that act as intermediaries and provide infrastruc- ture services: 576 | 577 | - Service invocation can be mediated by an *enterprise service bus* (ESB). An ESB routes messages between service consumers and service providers. In addition, an ESB can convert messages from one protocol or technology to another, perform various data transformations (e.g., format, content, split- ting, merging), perform security checks, and manage transactions. Using an ESB promotes interoperability, security, and modifiability. Of course, com- municating through an ESB adds overhead thereby lowering performance, and introduces an additional point of failure. When an ESB is not in place, service providers and consumers communicate with each other in a point- to-point fashion. 578 | 579 | - To improve the independence of service providers, a *service registry* can be used in SOA architectures. The registry is a component that allows services to be registered at runtime. This enables runtime discovery of services, which increases system modifiability by hiding the location and identity of the service provider. A registry can even permit multiple live versions of the same service. 580 | 581 | - An *orchestration server* (or orchestration engine) orchestrates the interac- tion among various service consumers and providers in an SOA system. It executes scripts upon the occurrence of a specific event (e.g., a purchase order request arrived). Applications with well-defined business processes or workflows that involve interactions with distributed components or systems gain in modifiability, interoperability, and reliability by using an orches- tration server. Many commercially available orchestration servers support various workflow or business process language standards. 582 | 583 | The basic types of connectors used in SOA are these: 584 | 585 | - *SOAP*. The standard protocol for communication in the web services tech- nology. Service consumers and providers interact by exchanging request/ reply XML messages typically on top of HTTP. 586 | 587 | - *Representational State Transfer (REST)*. A service consumer sends non- blocking HTTP requests. These requests rely on the four basic HTTP com- mands (POST, GET, PUT, DELETE) to tell the service provider to create, retrieve, update, or delete a resource. 588 | 589 | - *Asynchronous messaging*, a “fire-and-forget” information exchange. Participants do not have to wait for an acknowledgment of receipt, because the infrastructure is assumed to have delivered the message successfully. The messaging connector can be point-to-point or publish-subscribe. 590 | 591 | 592 | 593 | 594 | 595 | In practice, SOA environments may involve a mix of the three connectors just listed, along with legacy protocols and other communication alternatives (e.g., SMTP). Commercial products such as IBM’s WebSphere MQ, Microsoft’s MSMQ, or Apache’s ActiveMQ are infrastructure components that provide asyn- chronous messaging. SOAP and REST are described in more detail in Chapter 6. 596 | 597 | As you can see, the SOA pattern can be quite complex to design and im- plement (due to dynamic binding and the concomitant use of metadata). Other potential problems with this pattern include the performance overhead of the middleware that is interposed between services and clients and the lack of perfor- mance guarantees (because services are shared and, in general, not under control of the requester). These weaknesses are all shared with the broker pattern, which is not surprising because the SOA pattern shares many of the design concepts and goals of broker. In addition, because you do not, in general, control the evolution of the services that you use, you may have to endure high and unplanned-for maintenance costs. 598 | 599 | Table 13.7 summarizes the SOA pattern. 600 | 601 | The main benefit and the major driver of SOA is interoperability. Because service providers and service consumers may run on different platforms, ser- vice-oriented architectures often integrate a variety of systems, including legacy systems. SOA also offers the necessary elements to interact with external ser- vices available over the Internet. Special SOA components such as the registry or the ESB also allow dynamic reconfiguration, which is useful when there’s a need to replace or add versions of components with no system interruption. 602 | 603 | Figure 13.11 shows the SOA view of a system called Adventure Builder. Adventure Builder allows a customer on the web to assemble a vacation by choosing an activity and lodging at and transportation to a destination. The Ad- venture Builder system interacts with external service providers to construct the vacation, and with bank services to process payment. The central OPC (Order Processing Center) component coordinates the interaction with internal and ex- ternal service consumers and providers. Note that the external providers can be legacy mainframe systems, Java systems, .NET systems, and so on. The nature of these external components is transparent because SOAP provides the necessary interoperability. 604 | 605 | 606 | 607 | ##### Overview 608 | 609 | Computation is achieved by a set of cooperating components 610 | that provide and/or consume services over a network. The 611 | computation is often described using a workflow language. 612 | 613 | ##### Elements 614 | 615 | Components: 616 | 617 | - Service providers, which provide one or more services 618 | 619 | through published interfaces. Concerns are often tied to 620 | the chosen implementation technology, and include perfor- mance, authorization constraints, availability, and cost. In some cases these properties are specified in a service-level agreement. 621 | 622 | - Service consumers, which invoke services directly or through an intermediary. 623 | 624 | - Service providers may also be service consumers. 625 | 626 | - ESB, which is an intermediary element that can route and 627 | 628 | transform messages between service providers and consum- 629 | 630 | ers. 631 | 632 | - Registry of services, which may be used by providers to 633 | 634 | register their services and by consumers to discover services 635 | 636 | at runtime. 637 | 638 | - Orchestration server, which coordinates the interactions 639 | 640 | between service consumers and providers based on 641 | 642 | languages for business processes and workflows. Connectors: 643 | 644 | - SOAP connector, which uses the SOAP protocol for synchronous communication between web services, typically over HTTP. 645 | - REST connector, which relies on the basic request/reply operations of the HTTP protocol. 646 | - Asynchronous messaging connector, which uses a messaging system to offer point-to-point or publish-subscribe asynchronous message exchanges. 647 | 648 | 649 | 650 | ##### Relations 651 | 652 | Attachment of the different kinds of components available to the respective connectors 653 | 654 | 655 | 656 | ##### Constraints 657 | 658 | Service consumers are connected to service providers, but intermediary components (e.g., ESB, registry, orchestration server) may be used. 659 | 660 | 661 | 662 | ##### Weaknesses 663 | 664 | SOA-based systems are typically complex to build. 665 | You don’t control the evolution of independent services. 666 | 667 | There is a performance overhead associated with the middleware, and services may be performance bottlenecks, and typically do not provide performance guarantees. -------------------------------------------------------------------------------- /Software-Architecture/4. add_design.md: -------------------------------------------------------------------------------- 1 | # ADD 设计过程 2 | 3 | 个人感觉考的概率不是很大,毕竟大作业写过这个。 4 | 5 | 但是输入,输出和过程还是要背下来的。 6 | 7 | ### 1. 总体概览 8 | 9 | 设计活动的⽬的在于产生适应约束并达到系统质量和业务⽬标的设计。 10 | 11 | 在这个过程中,质量属性可以被分解和分配到要分解到元素中。 12 | 13 | 在分解要时刻注意去满足系统的约束。 14 | 15 | 16 | 17 | **ADD**(**Attribute-Driven Design**) 是 属性驱动设计方法 18 | 19 | ### 2. 过程 20 | 21 | 22 | 23 | #### 输⼊:功能需求、质量属性、约束 24 | 25 | 26 | 27 | #### 1. 确认有足够的需求信息 28 | 29 | 用 stimulus - response 的方法决定有没有足够的需求信息 30 | 31 | #### 2. 找到要去分解的系统元素 32 | 33 | 如果一开始 是 “green fileld” 所有的需求都直接被分配到整个系统 34 | 35 | 如果一开始是一个部分设计好的系统,选择系统的的一部分去继续设计。 36 | 37 | #### 3. 对选择好的元素确定 ASR 38 | 39 | 对所有的需求根据影响力进行排序 40 | 41 | 主要进行两个方面的排序, 一个是对 stake-holders 的影响力, 另一个是潜在的对架构设计的影响程度。 42 | 43 | #### 4. 选择满足 ASR 的设计概念 44 | 45 | ##### 4.1 找到设计的关键点 46 | 47 | 思考去如何去解决实际问题,列出几种方向上的方案 48 | 49 | ##### 4.2 找到对于每个设计点点候选的 Pattern 和 Tactics 50 | 51 | ##### 4.3 从列表中选择出合适的 patterns 和 tactics 52 | 53 | 思考在使用每种模式的时候会有什么不足,每种模式和其他的模式能不能合理的共存。 54 | 55 | ##### 4.4 决定 patterns ,tactics 和 ASR 的关系 56 | 57 | 选择出的模式和 tactics 的结合很可能会产生新的pattern 58 | 59 | ##### 4.5 描述出基本的架构视图 60 | 61 | 通过描述选择的模式来产生架构视图。 (不需要是完整的架构视图) 62 | 63 | ##### 4.6 评估和解决这个过程中产生的不一致 64 | 65 | 查看是有否有一些没有考虑到的架构驱动因素等。 66 | 67 | #### 5. 产生架构视图并且分配职责 68 | 69 | 产生架构分解视图并且从上到下的把架构职责进行分配。 70 | 71 | #### 6. 决定产生的元素的接口 72 | 73 | #### 7. 确认和精华需求并且为元素构造约束 74 | 75 | 确认所有的需求都已经被分配到了。 76 | 77 | #### 8 重复上述步骤知道所有的都已经被满足了。 78 | 79 | 80 | 81 | #### 输出 82 | 83 | 1. 软件元素, 一个可以满足不同的角色和职责的计算和开发单元, 有定义好的元素。 并且和其他的软件元素相关。 84 | 2. 角色: 一系列相关的职责 85 | 3. 职责: 软件元素提供的功能数据和信息。 86 | 4. 属性; 一个软件元素的其他信息 87 | 5. 关系: 软件元素如何和其他元素进行沟通的定义。 -------------------------------------------------------------------------------- /Software-Architecture/5. design_pattern.md: -------------------------------------------------------------------------------- 1 | # 设计模式 2 | 3 | 4 | 5 | 对于作家或者其他的文字工作者,他们的文字功底是不是好可以非常容易的被大家发现,也就是可以说对于写作,外在特征和内在特征是统一的, 作家和读者看到的都是文字。 6 | 7 | 但是对于软件开发者,开发者写的是源代码,经过编译部署之后用户使用的是系统。 通常用户并不能看到源代码,也就是对于软件开发外在特性和内在特性是相互隔离的。 8 | 9 | 外在特征: 正确性, 易用性, 效率, 可靠性,适应性, 完整性, 精确性,健壮性 10 | 11 | 内在特征: 可维护性, 灵活性, 可移植性, 可重用性,可读性,可测试性, 可理解性 12 | 13 | 虽然在内在特性非常差的情况下也可能会有好的外在特性,但是一个好的内在特性更有利于外在特征的实现,内在特征(源代码本身)是软件价值的十分重要的体现部分。 14 | 15 | 要充分尽可能的提高内在特性,软件构造一个比较困难的任务,需要单独仔细的研究,所以有《代码大全》,《设计模式》等很多书籍讲述如何设计高质量的软件。 16 | 17 | 18 | 19 | ### 一. 高质量的软件的特征 20 | 21 | 软件工程建模大师 peter Coad 认为一个好的系统三个特征 22 | 23 | - 可扩展性 : 系统增加功能时要增加的代码量和对原有功能的修改程度。 24 | - 灵活性: 当一个系统被用于其他用途时,系统要进行的修改程度。 25 | - 可插入性: 目前也没有完全理解, 可能Linux 操作系统可以轻松支持各种外部设备就是一种非常高的可插入性 26 | 27 | 28 | 29 | 上面的三条简单来说就是 **系统很容易的进行增加和修改功能**。 30 | 31 | 可以进一步说是在 **增加或修改功能的时候增和修改的代码尽可能少**。 32 | 33 | - 如果要增加的代码尽可能少,就需要有更好的可复用性。 这一般意味着要之前的代码要把各种不同的功能分成不同的方法和类。 (面向对象设计的单一职责原则,合成复用原则, 提高内聚性) 34 | - 如果想要修改的代码尽可能少,其实就是要减少耦和, 其实减小代码之前的相互依赖,比较 其实一个非常关键的部分。 找准系统的依赖类型。 按照系统的依赖类型设计进行最相关的设计。 (开闭原则, 依赖倒置原则) 35 | 36 | 37 | 38 | 所以其实目标也可以变成增加内聚性,减少耦合性。 39 | 40 | ### 二. 耦合和内聚 41 | 42 | 内聚性(模块内部元素彼此结合的紧密程度): 43 | 44 | 1. 功能内聚。 一个子程序仅仅执行一种操作,那么这里面的代码就是功能内聚的。 (一般较低层次的模块很容功能内聚,比如工具方法) 45 | 2. 顺序内聚。 子程序需要按特定的顺讯执行的操作,这些步骤共享数据,全部执行完毕后才能完成一项完整的功能。 (一个系统必定不是只有一个操作,所以必然要有方法是顺序内聚的,只要控制该方法内聚性不再降低就好) 46 | 3. 通信内聚性。 在一个子程序中,两个操作只是使用了相同的数据,而不存在其他的任何联系。 47 | 4. 临时内聚性。 因为需要同时执行才被放入同一个子程序。 (在初始化方法中必然存在) 48 | 5. 过程内聚性。 前后操作有顺序关系,但是并没有严格的后一个操作的输入必须是前一个操作的输出。 (比如文件读写的时候要先检查文件权限和是否存在,然后再进行相关操作。) 49 | 50 | 51 | 52 | 以上五种是 **可以接受的内聚性存在形式** 可以看到其中的联系 53 | 54 | - 一个实现功能的 **最小** 模块是功能内聚的 55 | - 一个更加复杂的功能会包含多种不同的功能内聚的模块。 56 | - 如果这些模块有先后顺序关系并且是相同的数据,就是顺序内聚。 57 | - 如果针对相同的数据,就是通信内聚。 58 | - 如果完全独立但是需要同时执行,就是临时内聚。 59 | - 如果有顺序关系但是没有数据的通信,就是过程内聚。 60 | 61 | 62 | 63 | 5. 逻辑内聚性。 用同一个控制流程来控制完全不同类型的操作, 仅仅是因为控制流才联系在一起。 通常事件处理器都会有这种问题。 个人认为可以用表驱动的方法解决,将事件处理器的解决方案作为数据? 64 | 6. 偶然内聚性,各个操作没有任何可以看到的关联。 65 | 66 | 67 | 68 | 耦合性(不同模块之前的相关程度): 69 | 70 | 1. 数据耦合: 不同的模块之前仅仅通过数据(比如参数)进行耦合。 71 | 72 | ```c 73 | double sqrt(int number); // 比如这个计算平方根,只传递数据,获取返回值。 74 | ``` 75 | 76 | 2. 印记耦合: 模块传递一个组合的数据结构,但是只有其中的一部分被用到了。 一般情况下两个模块之前如果传递的是一个数据结构而不仅仅是简单变量,就是印记耦合。 不可避免是因为能比较便利并且带来的危害相对较小。 77 | 78 | 3. 控制耦合: 一个模块向另一个模块发送控制命令。 和数据耦合的区别在于控制耦合以为着要对被控制的模块的实现方式有一定的了解,这也在一定程度上增加了耦合程度。 79 | 80 | 4. 外部耦合: 一组模块全部共享外部的数据格式,通信协议或者设备接口,一般发生在和外部设备进行通信的时候。 81 | 82 | 5. 公共耦合: 一组模块都访问同一个公共数据环境,则它们之间的耦合就称为公共耦合。 比如共同访问内存,共同的消息队列,全局的数据结构,都是公共耦合。 83 | 84 | 6. 内容耦合。 一个模块直接使用了另一个模块的代码,破坏了模块的封装性。 85 | 86 | 87 | 88 | 所以提高内聚和减小耦和成为一些软件设计方法的设计目标。 89 | 90 | 比如结构化编程中的子程序,面向对象编程中的类和接口。 封装,多态,继承。都有这样的作用。 91 | 92 | 93 | 94 | ### 三. 高质量面相对象的设计中的相关原则和思想。 95 | 96 | 97 | 98 | 面向对象编程的提出是为了让编写大型项目更加简单容易,同时也更容易的实现软件的高内在特性。 99 | 100 | 面向对象的类,将数据和方法组合在一起,在结构上实现了高内聚低耦合。 101 | 102 | 面向对象中的多态, 运行时有不同的执行策略, 在运行时实现了高内聚和低耦合。 103 | 104 | 但是面向对象中对象创建的过程中也有一些不可避免的耦合,这就设计到了对象创建时的相关技巧。 105 | 106 | 107 | 108 | 以上的三种情况也形成了设计模式中的三种设计模式大类。 109 | 110 | 创建型模式,结构型模式 和 对象行为模式。 当然这是后话,会在后面介绍这些设计模式。 111 | 112 | 113 | 114 | 在具体的设计模式之上人们也总结出了 **7**种 面向对象软件设计原则。 115 | 116 | 1. **单一职责原则**: 类的职责要单一,不能把太多的职责放在一个类中。 117 | 118 | 显然的一点是: 类的职责越多,被复用的可能性越小。 但是职责本身也并不容易确定,甚至在不同时期也不是固定的,所以发现类的不同职责并且分离需要设计人员有很强的分析设计能力和相关的重构经验。 119 | 120 | **访问者 模式就实现并满足了单一职责** 121 | 122 | 123 | 124 | 2. **开闭原则**: 一个软件实体对扩展是开放的,但是对修改是关闭的。 可以在不修改一个软件的实体的基础上去扩展软件的功能。 125 | 126 | 开闭原则非常理想化,但是实际中一般不太可能实现。 一般只能针对预期的软件变更满足开闭原则。 所以对软件预期的变更进行预测和控制就显的尤为重要。 实现开闭原则其实就是抽象化,把系统中的可变部分单独封装起来。 很多设计模式都和开闭原则有关,尤其是对象行为模式,比如状态模式,策略模式等等。 127 | 128 | **策略模式** 129 | 130 | 131 | 132 | 3. **里氏替换原则**; 在软件系统中。一个可以介绍基类的地方必然可以接受一个子类软件对象。 133 | 134 | 所有使用父类的地方必须能够透明地使用其子类的对象。 所以程序中可以尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类来替换父类。 135 | 136 | **简单工厂模式,工厂方法模式** 137 | 138 | 139 | 140 | 4. **依赖倒转原则**。 高层模块不应该依赖低级模块,它们都应该依赖抽象。 抽象不应该依赖细节,细节应该依赖于抽象。 意思就是针对接口编程,不要针对实现编程。 141 | 142 | 依赖倒转原则是很多设计模式实现的主要手段, 使用接口或者父类的方式进行抽象化。 143 | 144 | 依赖注入就是运用了依赖倒转? 这一点还要再理解一下。 145 | 146 | 147 | 148 | 5. **接口隔离原则**: 客户端不应该依赖那些不需要的接口,实际做法就是分割接口,其实很像是单一职责原则在接口上的特例。 149 | 150 | **适配器模式** 151 | 152 | 153 | 154 | 6. **合成复用原则**: 尽可能的使用组合,而不是继承来达到复用的目的。 155 | 156 | 继承实际上增加了结构上的耦合性,一般选用组合和聚合的方式去实现。 157 | 158 | 159 | 160 | 7. **迪米特法则**,不要和陌生人说话。 其实就是降低了一种耦合。 161 | 162 | **外观模式** 163 | 164 | 165 | 166 | ### 四. 涉及到的设计模式 167 | 168 | #### 1. 工厂相关模式 169 | 170 | ##### (1) 简单工厂模式 171 | 172 | ​ 这个模式在我们的 **软件构造** 课程中提到了,但是四人帮的书上并没有,可能也是觉得太过于简单了。 173 | 174 | ​ 简单工厂也被称为静态工厂模式,主要的作用是根据参数的不同返回不同的实例,被创建的实例往往有共同的父类。 175 | 176 | ​ 这个方法仔细思考一下就会觉得非常 Naive, 就是把业务代码中的if-else 判断转移到了工厂的代码中。 177 | 178 | ```java 179 | public class PayMethodFactory{ 180 | public static Abstract getPayMethod(String type){ 181 | if(type.equals("cash")){ 182 | return new Cashpay(); 183 | }else if(type.euqals("creditcard")){ 184 | return new Creditcardpay(); 185 | } 186 | ...... 187 | } 188 | } 189 | ``` 190 | 191 | ​ 这个模式显而易见的缺点是工厂的职责过重,一点需要增加新的产品,就要修改工厂代码里的逻辑,这违反了面向对象设计原则中的开闭原则。 192 | 193 | ​ 其实这个模式带来的优点就是划分了不同的职责,在一定程度上减小了耦合。 比如说原本是业务逻辑有耦合度A, 创建对象部分有耦合度B, 这两者中间还有一些耦合程度,采用了简单工厂模式后就把中间的耦合长度极大的减小了。 但是对于A 和 B本身的耦合程度却没有起到非常大的作用。 这也就是后面的工厂模式的来源吧。 194 | 195 | ​ 196 | 197 | **下面是Spring boot 源代码中一个简单工厂的例子** 198 | 199 | ```java 200 | // json 解析器工厂 根据不同的json实现选择不同的jsonpaser 201 | public abstract class JsonParserFactory { 202 | 203 | /** 204 | * Static factory for the "best" JSON parser available on the classpath. Tries Jackson 205 | * 2, then Gson, Snake YAML, Simple JSON, JSON (from eclipse), and then falls back to 206 | * the {@link BasicJsonParser}. 207 | * @return a {@link JsonParser} 208 | */ 209 | public static JsonParser getJsonParser() { 210 | if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) { 211 | return new JacksonJsonParser(); 212 | } 213 | if (ClassUtils.isPresent("com.google.gson.Gson", null)) { 214 | return new GsonJsonParser(); 215 | } 216 | if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { 217 | return new YamlJsonParser(); 218 | } 219 | if (ClassUtils.isPresent("org.json.simple.JSONObject", null)) { 220 | return new JsonSimpleJsonParser(); 221 | } 222 | return new BasicJsonParser(); 223 | } 224 | 225 | } 226 | ``` 227 | 228 | ##### (2) 工厂方法模式 229 | 230 | ​ 不再由一个统一的工厂去完成所有产品的创建,而是建立一个所有工厂的父类,将具体的对象创建的过程交给专门的工厂子类去完成。 这样就可以在不修改具体的工厂类的情况下引进新的产品,更加符合开闭原则。 231 | 232 | ​ 也叫虚拟构造器或者多态工厂模式。 233 | 234 | ```java 235 | public abstract class PayMethodFactory{ 236 | public abstract AbstractPay getPaymethod(); 237 | } 238 | 239 | public class CashPay extends PayMethodFactory{ 240 | public Abstractpay getPayMethod(){ 241 | return new CashPay(); 242 | } 243 | } 244 | 245 | 246 | CashPayFactory 247 | 248 | 249 | PayMethodFactory factory; 250 | AbstractPay payMethod; 251 | factory = (PayMethodFactory)XMLUtil.getBean(); 252 | payMethod = factory.getPayMethod(); 253 | patMethod.pay(; 254 | ``` 255 | 256 | 257 | 258 | 上面还有一个非常主要的思想是把具体对象的注入放到了XML中,利用反射的方法进行动态确定。 259 | 260 | 这样也让代码的可修改性非常强,实际应用中只需要更改外部配置就可以改变程序的行为。 261 | 262 | 工厂代码的一个缺点就是类的数量太多,所以后面也引入了新的抽象工厂模式。 263 | 264 | 265 | 266 | **下面是Spring Boot 源码中典型的工厂模式的应用** 267 | 268 | 首先是抽象类交互web服务器工厂的定义 269 | 270 | ```java 271 | public abstract class AbstractReactiveWebServerFactory 272 | extends AbstractConfigurableWebServerFactory 273 | implements ConfigurableReactiveWebServerFactory { 274 | 275 | public AbstractReactiveWebServerFactory() { } 276 | public AbstractReactiveWebServerFactory(int port) { 277 | super(port); 278 | } 279 | } 280 | 281 | ``` 282 | 283 | 但是在其中并没有看见创建方法,实际上创建方法在其中的接口里,接口还有继承结构,这里直接给出。 284 | 285 | ```java 286 | public interface ConfigurableReactiveWebServerFactory 287 | extends ConfigurableWebServerFactory, ReactiveWebServerFactory { 288 | } 289 | 290 | public interface ReactiveWebServerFactory { 291 | 292 | WebServer getWebServer(HttpHandler httpHandler); 293 | } 294 | public interface WebServer { 295 | 296 | void start() throws WebServerException; 297 | void stop() throws WebServerException; 298 | int getPort(); 299 | 300 | } 301 | ``` 302 | 303 | 经过两层的寻找之后,终于找到了创建WebServer 的方法,所以上面的抽象类是有创建对象的方法的。 304 | 305 | 我们不难发现, WebServer 也是一个接口抽象类,所以也和工厂模式相符合。 306 | 307 | 下面去寻找具体工厂。 308 | 309 | ```java 310 | public class TomcatReactiveWebServerFactory extends AbstractReactiveWebServerFactory 311 | implements ConfigurableTomcatWebServerFactory { 312 | 313 | @Override 314 | public WebServer getWebServer(HttpHandler httpHandler) { 315 | Tomcat tomcat = new Tomcat(); 316 | File baseDir = (this.baseDirectory != null) ? this.baseDirectory 317 | : createTempDir("tomcat"); 318 | tomcat.setBaseDir(baseDir.getAbsolutePath()); 319 | Connector connector = new Connector(this.protocol); 320 | tomcat.getService().addConnector(connector); 321 | customizeConnector(connector); 322 | tomcat.setConnector(connector); 323 | tomcat.getHost().setAutoDeploy(false); 324 | configureEngine(tomcat.getEngine()); 325 | TomcatHttpHandlerAdapter servlet = new TomcatHttpHandlerAdapter(httpHandler); 326 | prepareContext(tomcat.getHost(), servlet); 327 | return new TomcatWebServer(tomcat, getPort() >= 0); 328 | } 329 | } 330 | 331 | public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory { 332 | @Override 333 | public WebServer getWebServer(HttpHandler httpHandler) { 334 | HttpServer httpServer = createHttpServer(); 335 | ReactorHttpHandlerAdapter handlerAdapter = new ReactorHttpHandlerAdapter( 336 | httpHandler); 337 | return new NettyWebServer(httpServer, handlerAdapter, this.lifecycleTimeout); 338 | } 339 | } 340 | ``` 341 | 342 | 343 | 344 | 这里省略了其他的东西,只保留了我们要看的创建方法。 这里分别是创建 Tomcat 和 Netty 的服务器的方法。 345 | 346 | 347 | 348 | 总结: 开始的时候不太理解工厂模式,看了 Spring Boot 这样比较大的项目之后有一点点的体会了。 不同的 WebServer 是一个非常复杂的对象,并且有非常复杂的继承体系。 349 | 350 | ​ 并且在创建对象的时候需要一些很复杂的操作,添加其他的属性等等,这些操作放进具体的对象和业务逻辑代码中又会造成非常大的耦合性,这些放到继承的工厂中可以很好的减小耦合,所以采用了继承的工厂结构。 351 | 352 | 353 | 354 | ##### (3) 抽象工厂模式 355 | 356 | ​ 应用了一类比较具体特定的应用场景,有时候需要一个工厂可以提供多个产品对象,不是单一的产品对象。 357 | 358 | ​ 产品的等级结构: 产品的继承结构。 比如电视机和具体的电视机产品之间就有一个产品的继承结构。 359 | 360 | ​ 产品族: 同一个工厂生产的,位于不同产品等级结构中的一组产品。 比如海尔电器工厂会生产海尔电视机,海尔电冰箱等,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。 361 | 362 | ​ 何时使用抽象工厂模式: 当系统提供的工厂产品不是一个简单的对象,而是位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。 363 | 364 | ​ 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。 365 | 366 | ```java 367 | // 一个抽象工厂类 368 | public abstract class AbstractFactory{ 369 | public abstract AbstractProductA createProductA(); 370 | public abstract AbstractProductB createProductB(); 371 | } 372 | 373 | // 一个具体工厂类 374 | public class ConcreteFactory1 extends AbstractFactory{ 375 | public AbstractProductA creatrProdectA(){ 376 | return new ConcreteProductA1(); 377 | } 378 | public AbstratProductB createProductB()P{ 379 | return new ConcreteProductB1(); 380 | } 381 | } 382 | ``` 383 | 384 | 也就是说抽象工厂的特点是同时生产类一系列配套的产品, 而不是像工厂模式那样只生产一种产品。 385 | 386 | 重点: **和工厂模式最大的不同是一个工厂里面生成的是一系列产品**。 387 | 388 | 389 | 390 | **java 源代码中工厂模式实现的例子** 391 | 392 | 下面是一个 java 源代码中 **抽象工厂** 模式的实现例子, java 是一个跨平台语言。 在不同的平台上一些底层的代码必然要有不同的实现, 但是这些方法的接口都是一样的。 下面对源代码进行简单的说明。 393 | 394 | 首先是 **抽象工厂类** 的声明, 可以看到其中用到了反射的方法进行创建对象,和上面的工厂方法中的讲解一致。 395 | 396 | ```java 397 | public abstract class PlatformFactory { 398 | private static PlatformFactory instance; 399 | public static synchronized PlatformFactory getPlatformFactory() { 400 | if (instance == null) { 401 | try { 402 | String platform = Platform.determinePlatform(); // 获得具体的平台 403 | String factory = "com.sun.glass.ui." + platform.toLowerCase(Locale.ROOT) + "."+ platform + "PlatformFactory"; // 生成具体的平台工厂。 404 | // System.out.println("Loading Glass Factory " + factory); 405 | Class c = Class.forName(factory); 406 | instance = (PlatformFactory) c.newInstance(); // 采用反射的方法进行创建 407 | } catch (Exception e) { 408 | e.printStackTrace(); 409 | System.out.println("Failed to load Glass factory class"); 410 | } 411 | } 412 | return instance; 413 | } 414 | // 下面是一些不同平台上要实现的相同操作 415 | public abstract Application createApplication(); 416 | public abstract MenuBarDelegate createMenuBarDelegate(MenuBar menubar); 417 | public abstract MenuDelegate createMenuDelegate(Menu menu); 418 | public abstract MenuItemDelegate createMenuItemDelegate(MenuItem menuItem); 419 | public abstract ClipboardDelegate createClipboardDelegate(); 420 | } 421 | ``` 422 | 423 | 下面是 windows 上具体工厂类的声明 424 | 425 | ```java 426 | // 下面就是 windows 的具体工厂类 427 | public final class WinPlatformFactory extends PlatformFactory { 428 | 429 | @Override public WinApplication createApplication() { 430 | return new WinApplication(); 431 | } 432 | 433 | @Override public MenuBarDelegate createMenuBarDelegate(MenuBar menubar) { 434 | return new WinMenuBarDelegate(menubar); 435 | } 436 | 437 | @Override public MenuDelegate createMenuDelegate(Menu menu) { 438 | return new WinMenuDelegate(menu); 439 | } 440 | 441 | @Override public MenuItemDelegate createMenuItemDelegate(MenuItem item) { 442 | return new WinMenuItemDelegate(item); 443 | } 444 | 445 | @Override public ClipboardDelegate createClipboardDelegate() { 446 | return new WinClipboardDelegate(); 447 | } 448 | } 449 | ``` 450 | 451 | 下面是 Mac 的具体工厂类 452 | 453 | ```java 454 | public final class MacPlatformFactory extends PlatformFactory { 455 | 456 | @Override public Application createApplication(){ 457 | return new MacApplication(); 458 | } 459 | 460 | @Override public MenuBarDelegate createMenuBarDelegate(MenuBar menubar) { 461 | return new MacMenuBarDelegate(); 462 | } 463 | 464 | @Override public MenuDelegate createMenuDelegate(Menu menu) { 465 | return new MacMenuDelegate(menu); 466 | } 467 | 468 | @Override public MenuItemDelegate createMenuItemDelegate(MenuItem item) { 469 | return new MacMenuDelegate(); 470 | } 471 | 472 | @Override public ClipboardDelegate createClipboardDelegate() { 473 | return new MacClipboardDelegate(); 474 | } 475 | } 476 | 477 | 478 | ``` 479 | 480 | 总结: java 中的具体例子可以让我们更加直观的看到抽象工厂模式的具体内涵,所以如果以后看到像这样的继承产品族就可以考虑去使用 **抽象工厂模式**。 481 | 482 | 483 | 484 | #### 2. 策略模式 485 | 486 | ##### 模式动机 487 | 488 | 有许多算法可以实现某一功能,如查找、排序等,将这些算法硬编码在它们的类或者一个类中是不可取的。 489 | 为了解决这些问题,我们可以定义一些独立的类来封装不同的算法,每一个封装算法的类我们都可以称之为策略(Strategy),为了保证这些策略的一致性我们一般会有一个抽象的策略用来做规则的定义,而具体每种算法则对应于一个具体策略。 490 | 491 | ##### 模式定义 492 | 493 | 策略模式(Strategy Pattern):定义一系列算法,并将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。它的别名有政策模式(Policy)。策略模式是一种对象行为型模式。 494 | 495 | ##### 参与者 496 | * Context:环境类 497 | * Strategy:抽象策略类 498 | * ConcreteStrategy:具体策略类 499 | 500 | ##### 模式优点 501 | 502 | * 策略模式提了管理相关的算法族的办法。 503 | * 策略模式提供了可以替换继承关系的办法。 504 | * 使用策略模式可以避免使用多重条件转移语句。 505 | 506 | ##### 模式缺点 507 | 508 | * 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。 509 | * 策略模式造成很多的策略类。 510 | 511 | ##### 模式使用 512 | 513 | * 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用 514 | 策略模式可以动态地让一个对象在许多行为中选择一种行为。 515 | * 一个系统需要动态地在几种算法中选择一种。 516 | * 一个系统的算法使用的数据不可以让客户端知道。 517 | * 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重 518 | 的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体 519 | 策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象 520 | 设计的概念。 521 | 522 | 523 | 524 | #### 3. 访问者模式 525 | 526 | ##### 模式动机 527 | 528 | 对象结构中存储了多种不同类型的对象信息, 对同一对象结构中的元素的操作方式并不唯一,可能需 529 | 要提供多种不同的处理方式, 还有可能增加新的处理方式 530 | 531 | ##### 模式定义 532 | 533 | 表示一个作用于某对象结构中的各个元素的操作。访问者模式让你可以在不改变各元素的类的前提下定 534 | 义作用于这些元素的新操作。 535 | 536 | ##### 参与者 537 | 538 | * Visitor(抽象访问者) 539 | * ConcreteVisitor(具体访问者) 540 | * Element(抽象元素) 541 | * ConcreteElement(具体元素) 542 | * ObjectStructure(对象结构) 543 | 544 | ##### 模式优点 545 | 546 | * 增加新的访问操作很方便 547 | * 将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰。 548 | * 让用户能够在不修改现有元素类层次结构的情况下,定义作用于该层次结构的操作。 549 | 550 | ##### 模式缺点 551 | 552 | * 增加新的元素类很困难 553 | * 破坏封装 554 | 555 | ##### 模式使用 556 | 557 | * 一个对象结构包含多个类型的对象,希望对这些对象实施一些依赖其具体类型的操作 558 | * 需要对一个对象结构中的对象进行很多不同的且不相关的操作,并需要避免让这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类 559 | * 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作 560 | 561 | 562 | 563 | #### 4. 外观模式 564 | 565 | ##### 模式动机 566 | 567 | * 一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现 568 | * 引入一个新的外观类(Facade)来负责和多个业务类【子系统(Subsystem)】进行交互,而客户类只需与外观类交互 569 | * 为多个业务类的调提供了一个统一的入口,简化了类与类之间的交互 570 | 571 | ##### 模式定义 572 | 573 | 为子系统中的一组接提供一个统一的入口。 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 574 | 575 | * 又称为门面模式 576 | * 是迪米特法则的一种具体实现 577 | * 通过引入一个新的外观角色来降低原有系统的复杂度,同时降低客户类与子系统的耦合度 578 | * 所指的子系统是一个广义的概念,它可以是一个类、一个功能模块、系统的一个组成部分或者一个完整的系统 579 | 580 | ##### 参与者 581 | 582 | * Facade(外观角色) 583 | * SubSystem(子系统角色) 584 | 585 | ##### 模式优点 586 | 587 | * 它对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易 588 | * 它实现了子系统与客户端之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整外观类即可 589 | * 一个子系统的修改对其他子系统没有任何影响,而且子系统的内部变化也不会影响到外观对象 590 | 591 | ##### 模式缺点 592 | 593 | * 不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多的限制则减少了可变性和灵活性 594 | * 如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则 595 | 596 | ##### 模式使用 597 | 598 | * 要为访问一系列复杂的子系统ᨀ供一个简单入口 599 | * 客户端程序与多个子系统之间存在很大的依赖性 600 | * 在层次化结构中,可以使用外观模式的定义系统中每一层的入口,层与层之间不直接产生联系,而是通过外观类建立联系,降低层之间的耦合度 601 | 602 | 603 | 604 | #### 4. 适配器模式 605 | 606 | ##### 模式动机 607 | 608 | * 在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。 609 | * 适配提供客户类需要的接口,适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。 610 | * 适配器可以使由于接口不兼容而不能交互的类可以一起工作。这就是适配器模式的模式动机。 611 | 612 | ##### 模式定义 613 | 614 | 适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 615 | 616 | ##### 参与者 617 | 618 | * Target:目标抽象类 619 | * Adapter:适配器类 620 | * Adaptee:适配者类 621 | * Client:客户类 622 | 623 | ##### 模式优点 624 | 625 | * 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无需修改原有代码。 626 | * 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且ᨀ高了适配者的复用性。 627 | * 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。 628 | 629 | ##### 模式缺点 630 | 631 | * 对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。 632 | * 与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。 633 | 634 | ##### 模式使用 635 | 636 | * 系统需要使用现有的类,而这些类的接口不符合系统的需要。 637 | * 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联 638 | 的一些类,包括一些可能在将来引进的类一起工作。 639 | 640 | -------------------------------------------------------------------------------- /Software-Architecture/6. documenting.md: -------------------------------------------------------------------------------- 1 | # 文档化部分 2 | 3 | ### 1. ⽂档化的好处 4 | 5 | 1. 更好地交流设计决策 6 | 2. 帮助理解决策 7 | 3. 更新设计者的思维 8 | 4. 锻炼设计架构的能力 9 | 5. 支持地理分布的团队 10 | 11 | ### 2. 文档化的一些不足(挑战): 12 | 13 | 1. 没有标准化 14 | 2. 对于大型系统⼗分耗时 15 | 3. 对视图的数量和本质没有达到共识 16 | 4. 缺乏一整套标记语言和⼯具来全⾯描述架构所做的所有决定 17 | 5. 易受ddl的不良影响 18 | 19 | ### 3. 文档内容: 20 | 21 | 1. 组件接口和依赖 22 | 2. ⼦系统约束 23 | 3. 测试场景 24 | 4. 设计的系统和周围环境的关系 25 | 26 | ### 4. 架构文档需要遵守的7条规则: 27 | 28 | 1. 从读者⻆角度书写⽂文档 29 | 2. 避免不必要的重复 30 | 3. 避免歧义 31 | 4. 标准化组织 (Beyond) 32 | 5. 记录架构决定背后的原因 33 | 6. ⽂档尽可能保持较新的状态 34 | 7. 审查文档是否与目的相符 35 | 36 | ### 5. Views 37 | 38 | #### 1. style 连线题 39 | 40 | 这个老师在课堂上提问过,也在之前的考试中出现过,可以说是比较重要的。 41 | 42 | 1. How it structed as a set of implementaion ———— Module styles 43 | 2. How it is structed as a set of elements taht have runtime behavior and interactions C&C styles 44 | 3. How it relates to non-software structures in its environment ——— Allocation styles 45 | 46 | #### 2. style 和 view 之间的关系 47 | 48 | Style: 关注组件和组件之间的交互和职责限制。更关注架构方法,不包含具体的上下文和 49 | 问题。 50 | Pattern: 体现软件系统基本的结构组织模式。关注上下⽂和问题,以及如何解决。 51 | View: 是系统中特定类型的元素及其关系的表示。不同的视图⽀持不同的⽬标和⽤户,强调不同的系统元素和关系,同时在不同程度上表示不同的质量属性。 52 | 53 | 54 | 55 | #### 3. View 本身和多样化的原因 56 | 57 | A software architecture is a complex entity that can not be described in a simple one-dimensional fashion. 58 | 59 | **A view is a representation of a set of system elements and relations among them not all system elements, but those of a particular type.** 60 | 61 | For example, a layered view of a system would show elements of type “layer” that is, it would show the system’s decomposition into layers and the relations among those layers. A pure layered view would not, however, show the system’s services, or clients and servers, or data model, or any other type of element. 62 | 63 | Thus, views let us divide the multidimensional entity that is a software architecture into a number of (we hope) interesting and manageable representations of the system. The concept of *views* gives us our most fundamental principle of architecture documentation: 64 | 65 | **Documenting an architecture is a matter of documenting the relevant views and then adding documentation that applies to more than one view.** 66 | 67 | This maxim gives our approach to documentation its name: *Views and Beyond*. 68 | 69 | Different views also expose different quality attributes to different degrees. 70 | 71 | **Therefore, the quality attributes that are of most concern to you and the other stakeholders in the system’s development will affect the choice of what views to document.** For instance, a layered view will let you reason about your system’s portability, a deployment view will let you reason about your system’s performance and reliability, and so forth. 72 | 73 | 74 | 75 | #### 4. Module View 76 | 77 | * Decomposition view 78 | * Uses view 79 | * Generalization view 80 | * Layered view 81 | * Aspects view 82 | * Data model view 83 | 84 | 85 | 86 | A module is an implementation unit that provides a coherent set of responsibilities. 87 | 88 | 89 | 90 | It is unlikely that the documentation of any software architecture can be complete without at least one module view. 91 | 92 | 93 | 94 | ##### Elements 95 | 96 | Modules, which are implementation units of software that provide a coherent set of responsibilities. 97 | 98 | ##### Relations 99 | 100 | * Is part of, which defines a part/whole relationship between the submodule—the part—and the aggregate module—the whole. 101 | 102 | * Depends on, which defines a dependency relationship be- tween two modules. Specific module views elaborate what dependency is meant. 103 | 104 | * Is a, which defines a generalization/specialization relation- ship between a more specific module—the child—and a more general module—the parent. 105 | 106 | ##### Constraints 107 | 108 | Different module views may impose specific topological constraints, such as limitations on the visibility between modules. 109 | 110 | ##### Usage 111 | 112 | * Blueprint for construction of the code 113 | * Change-impact analysis 114 | * Planning incremental development 115 | * Requirements traceability analysis 116 | * Communicating the functionality of a system and the structure of its code base 117 | * Supporting the definition of work assignments, implementation schedules, and budget information 118 | * Showing the structure of information that the system needs to manage 119 | 120 | 121 | 122 | #### 5. component-and-connector Views 123 | 124 | 125 | 126 | * Pipe-and-filter view 127 | * Client-server view 128 | * Peer-to-peer view 129 | * Service-oriented architecture view 130 | * Publish-Subscribe view 131 | * shared-data view 132 | * multi-tier view 133 | 134 | 135 | 136 | Component-and-connector views show elements that have some runtime presence, such as processes, objects, clients, servers, and data stores. 137 | 138 | Components have interfaces called *ports*. A port defines a point of potential interaction of a component with its environment. A port usually has an explicit type, which defines the kind of behavior that can take place at that point of interaction. A component may have many ports of the same type, each forming a 139 | different input or output channel at runtime. In this respect ports differ from interfaces of modules, whose interfaces are never replicated. You can annotate a port with a number or range of numbers to indicate replication; for example, “1..4” might mean that an interface could be replicated up to four times. A component’s ports should be explicitly documented, by showing them in the diagram and de- 140 | fining them in the diagram’s supporting documentation. 141 | 142 | The primary relation within a C&C view is *attachment*. *Attachments* indicate which connectors are attached to which components, thereby defining a system as a graph of components and connectors. Specifically, an attachment is denoted by associating (attaching) a component’s port to a connector’s role. 143 | 144 | 145 | 146 | ##### Elements 147 | 148 | ■ Components. Principal processing units and data stores. A compo-nent has a set of ports through which it interacts with other components (via connectors). 149 | 150 | ■ Connectors. Pathways of interaction between components. Connec tors have a set of roles (interfaces) that indicate how components may use a connector in interactions. 151 | 152 | ##### Relations 153 | 154 | * Attachments. Component ports are associated with connector roles to yield a graph of components and connectors*.* 155 | 156 | * Interface delegation. In some situations component ports are associated with one or more ports in an “internal” subarchitecture. The case is similar for the roles of a connector. 157 | 158 | 159 | 160 | ##### Constraints 161 | 162 | Components can only be attached to connectors, not directly to other components. 163 | 164 | - Connectors can only be attached to components, not directly to other 165 | 166 | connectors. 167 | 168 | - Attachments can only be made between compatible ports and roles. 169 | 170 | - Interface delegation can only be defined between two compatible 171 | 172 | ports (or two compatible roles). 173 | 174 | - Connectors cannot appear in isolation; a connector must be attached 175 | 176 | to a component 177 | 178 | ##### Usage 179 | 180 | * Show how the system works. 181 | 182 | - Guide development by specifying structure and behavior of runtime 183 | 184 | elements. 185 | 186 | - Help reason about runtime system quality attributes, such as perfor- mance and availability. 187 | 188 | 189 | 190 | #### 6. Allocation Views 191 | 192 | 193 | 194 | * Deployment view 195 | * Install view 196 | * Work assignment view 197 | * other allocation views 198 | 199 | 200 | 201 | **Allocation views describe the mapping of software units to elements of an environment in which the software is developed or in which it executes.** The environment might be the hardware, the operating environment in which the software is executed, the file systems supporting development or deployment, or the development organization(s). 202 | 203 | Software elements and environmental elements have properties in allocation views. 204 | 205 | **The usual goal of an allocation view is to compare the properties required by the software element with the properties *provided* by the environmental elements to determine whether the allocation will be successful or not.** 206 | 207 | For example,to ensure a component’s *required* response time, it has to execute on (be allocated 208 | to) a processor that *provides* sufficiently fast processing power. For another example, a computing platform might not allow a task to use more than 10 kilobytes of virtual memory. An execution model of the software element in question can be used to determine the required virtual memory usage. Similarly, if you are 209 | migrating a module from one team to another, you might want to ensure that the new team has the appropriate skills and background knowledge. 210 | 211 | 212 | 213 | **Allocation views can depict static or dynamic views.** 214 | 215 | A static view depicts a fixed allocation of resources in an environment. A dynamic view depicts the conditions and the triggers for which allocation of resources changes according to loading. Some systems recruit and utilize new resources as their load increases. An example is a load-balancing system in which new processes or threads are created on another machine. In this view, the conditions under which the allocation changes, the allocation of runtime software, and the dynamic allocation mechanism need to be documented. (Recall from Chapter 1 that one of the allocation structures is the work assignment structure, which allocates modules to teams for development. That 216 | relationship, too, can be allocated dynamically, depending on “load”—in this case, the load on development teams.) 217 | 218 | ##### Elements 219 | 220 | ■ Software element. A software element has properties that are required of the environment. 221 | 222 | ■ Environmental element. An environmental element has properties that are provided to the software. 223 | 224 | ##### Relations 225 | 226 | Allocated to. A software element is mapped (allocated to) an environmental element. Properties are dependent on the particular view. 227 | 228 | ##### Constraints 229 | 230 | Varies by view 231 | 232 | ##### Usage 233 | 234 | * For reasoning about performance, availability, security, and safety. 235 | * For reasoning about distributed development and allocation of work to teams. 236 | * For reasoning about concurrent access to software versions. 237 | * For reasoning about the form and mechanisms of system installation. 238 | 239 | 240 | 241 | #### 7. Quality Views 242 | 243 | **Module, C&C, and allocation views are all structural views: They primarily show the structures that the architect has engineered into the architecture to satisfy functional and quality attribute requirements.** 244 | 245 | These views are excellent for guiding and constraining downstream developers, whose primary job it is to implement those structures. However, in systems in which certain quality attributes (or, for that matter, some other kind of stakeholder concerns) are particularly important and pervasive, structural views may not be the best way to present the architectural solution to those needs. The reason is that the solution may be spread across multiple structures that are inconvenient to combine (for example, because the element types shown in each are different). 246 | 247 | Another kind of view, which we call a *quality view*, can be tailored for specific stakeholders or to address specific concerns. These quality views are formed by extracting the relevant pieces of structural views and packaging them together. 248 | Here are five examples: 249 | 250 | * A *security view* 251 | * A *communications view* 252 | * An *exception* or *error-handling view* 253 | * A *reliability* view 254 | * A *performance* view 255 | 256 | 257 | 258 | ### 6. 对 view 进行文档化 259 | 260 | 重点在选择 view 和 对 view 进行合并 261 | 262 | At a minimum, expect to have at least one module view, at least one C&C view, and for larger systems, at least one allocation view in your architecture doc- ument. Beyond that basic rule of thumb, however, there is a three-step method for choosing the views: 263 | 264 | #### Step 1: Build a stakeholder/view table. 265 | 266 | **Enumerate the stakeholders for your project’s software architecture documentation down the rows.** Be as comprehensive as you can. For the columns, enumerate the views that apply to your system. (Use the structures discussed in Chapter 1, the views discussed in this chapter, and the views that your design work in ADD has suggested as a starting list of candidates.) Some views (such as decom- position, uses, and work assignment) apply to every system, while others (various C&C views, the layered view) only apply to some systems. **For the columns, make sure to include the views or view sketches you already have as a result of your design work so far.** 267 | 268 | Once you have the rows and columns defined, fill in each cell to describe how much information the stakeholder requires from the view: none, overview only, moderate detail, or high detail. The candidate view list going into step 2 now consists of those views for which some stakeholder has a vested interest. 269 | 270 | ####Step 2: Combine views. 271 | 272 | The candidate view list from step 1 is likely to yield an impractically large number of views. This step will winnow the list to manageable size. Look for marginal views in the table: those that require only an overview, or that serve very few stakeholders. **Combine each marginal view with another view that has a stronger constituency.** 273 | 274 | #### Step 3: Prioritize and stage. 275 | 276 | After step 2 you should have the minimum set of views needed to serve your stakeholder community. At this point you need to decide what to do first. What you do first depends on your project, but here are some things to consider: 277 | 278 | - The decomposition view (one of the module views) is a particularly helpful view to release early. High-level (that is, broad and shallow) decompositions are often easy to design, and with this information the project manager can start to staff development teams, put training in place, determine which parts to outsource, and start producing budgets and schedules. 279 | - Be aware that you don’t have to satisfy all the information needs of all the stakeholders to the fullest extent. Providing 80 percent of the information goes a long way, and this might be good enough so that the stakeholders can do their job. Check with the stakeholder to see if a subset of informa- tion would be sufficient. They typically prefer a product that is delivered on time and within budget over getting the perfect documentation. 280 | - You don’t have to complete one view before starting another. People can make progress with overview-level information, so a breadth-first ap- proach is often the best. 281 | 282 | 283 | 284 | ### 7. Beyond 285 | 286 | As shown in Figure 18.4, documentation beyond views can be divided into two parts: 287 | 288 | 1. 1. *Overview of the architecture documentation.* This tells how the documen- tation is laid out and organized so that a stakeholder of the architecture can find the information he or she needs efficiently and reliably. 289 | 2. *Information about the architecture.* Here, the information that remains to be captured beyond the views themselves is a short system overview to ground any reader as to the purpose of the system and the way the views are related to one another, an overview of and rationale behind systemwide design approaches, a list of elements and where they appear, and a glossary and an acronym list for the entire architecture. -------------------------------------------------------------------------------- /Software-Architecture/7. evaluation.md: -------------------------------------------------------------------------------- 1 | # ATAM 设计 2 | 3 | 4 | 5 | ### 1. 为什什么要评估? 6 | 7 | 1. ⼤型项⽬经常迟交和超支 8 | 2. 项目进行过程中有时候要重新设计 9 | 3. 能够帮助尽早发现问题,尽早发现的解决成本是很低的 10 | 4. 传播架构设计的最佳实践 11 | 5. 提供优秀项目技术管理 12 | 13 | 14 | 15 | ### 2. 如何评估? 16 | 17 | 1. 发现⻛险点 18 | 2. 识别出错误的架构选择 19 | 3. 保证解决了了质量属性 20 | 21 | 有很多成型的方法来解决这个问题,大部分都是基于场景进行的。 22 | 23 | 24 | 25 | 可以帮助 stakeholder 去尽早的问出合适的问题来: 26 | 27 | 1. 找到风险, 找到对所需质量属性有消极影响的架构决定 28 | 2. 找到敏感点: 对于特定质量属性敏感的架构决定(⼩小改动、造成很⼤大影响) 29 | 3. 找到tradeoffs: 影响多个质量量属性的架构决定 30 | 31 | 32 | 33 | ### 3. ATAM过程: 34 | 35 | #### Phase 0 :参与者和准备阶段 36 | 37 | ###### 参与者: 评估⼩组长和关键的项⽬决策者 38 | 39 | ###### 输⼊:架构⽂档 40 | 41 | ###### 输出: 评估计划: 谁、什么时间、提供什么样子的评估报告 42 | 43 | 44 | 45 | #### Phase 1:评估(1) 46 | ###### 参与者:评估小组和项目设计决策者(肯定包括了项⽬经理和架构师) 47 | 48 | ###### 输出: 架构简要展示、业务目标、质量属性和相关场景、效⽤用树、⻛险和非⻛险点、敏感点、权衡点 49 | 50 | ###### Step 1: 介绍ATAM⽅法(评估小组长) 51 | 52 | ###### Step 2: 介绍商业动机(项⽬经理或系统客户) 53 | 54 | ###### Step 3: 介绍架构(⾸席结构师) 55 | 56 | ###### Step 4:识别使用的架构方法(评估小组) 57 | 58 | ###### Step 5:⽣成质量属性效⽤树(评估⼩组和项目设计决策者) 决定性的一步 59 | 60 | ###### Step 6:分析架构⽅法(评估小组) 确保方法是正确的 获得风险点、⾮风险点、敏感点和权衡点列表 61 | 62 | ​ 63 | 64 | #### Phase 2:评估(2) 65 | 66 | ###### 参与者: 评估小组、项⽬设计决策者和架构涉众 67 | 68 | ###### 输出: 从涉众群体获得的一个优先级场景列表、风险主题和商业动机 69 | 70 | ###### Step 1: 介绍ATAM⽅法和之前的结果(评估小组长) 重复以确保涉众也知道方法并回顾分享之前2~6步的结果 71 | 72 | ###### Step 7:头脑风暴、场景划分优先级(评估⼩组问涉众) 与质量属性效⽤树进行⽐对 73 | 74 | ###### Step 8:分析架构⽅方法(评估小组、架构师) 使用新产生的优先级靠前的场景、架构师解释与之相关的架构决定 75 | 76 | ###### Step 9:展示结果(评估小组) 77 | 78 | 79 | 80 | #### Phase 3:后续⼯工作 Follow up 81 | 82 | ###### 参与者:评估⼩小组和主要涉众 83 | 84 | ###### 输出:最终的评估报告 85 | 86 | 87 | 88 | #### ATAM 输出 89 | ###### 架构简要介绍 90 | 91 | ###### 业务⽬目标 92 | 93 | ###### 以质量属性场景表示的带优先级的质量属性需求 94 | 95 | ###### 效用树 96 | 97 | ###### ⼀系列⻛险点和非风险点 98 | 99 | ###### 风险主题 100 | 101 | ###### 架构决定与质量需求之间的映射 102 | 103 | ###### 敏感点、权衡点 104 | 105 | ###### 最终评估报告 -------------------------------------------------------------------------------- /Software-Architecture/8 . 软件产品线(课本描述).md: -------------------------------------------------------------------------------- 1 | # 软件产品线(课本描述) 2 | 3 | A software architecture represents a significant investment of time and effort,usually by senior talent. So it is natural to want to maximize the return on this investment by reusing an architecture across multiple systems. 4 | 5 | There are many ways this happens in practice. The patterns we discussed in Chapter 13 are a big step in this direction; using a pattern is reusing a package of architectural decisions (albeit not a complete architecture). And strictly speaking, every time you make a change to a system, you are reusing its architecture (or whatever portion of its architecture you don’t have to change). 6 | 7 | This chapter shows yet another way to reuse a software architecture (and many other assets as well) across a family of related systems, and the benefits that doing so can bring. Many software-producing organizations tend to produce systems or products that resemble each other more than they differ. This is an opportunity for reusing the architecture across these similar products. These software product lines simplify the creation of new members of a family of similar systems. 8 | 9 | This kind of reuse has been shown to bring substantial benefits that include reduced cost of construction, higher quality, and greatly reduced time to market. 10 | 11 | The Software Engineering Institute defines a software product line as “a set of software-intensive systems sharing a common, managed set of features that satisfy the specific needs of a particular market segment or mission and that are developed from a common set of core assets in a prescribed way.” 12 | 13 | The vision is of a set of reusable assets (called core assets) based on a common architecture and the software elements that populate that architecture. The core assets also include designs and their documentation, user manuals, project management artifacts such as budgets and schedules, software test plans and test cases, and more. 14 | 15 | The product line approach works because the core assets were built specifi- cally to support multiple members of the same family of products. Hence, reusing them is faster and less expensive than reinventing those software assets for each new product or system in the organization’s portfolio. Core assets, including the architecture, are usually designed with built-in variation points—places where they can be quickly tailored in preplanned ways. 16 | 17 | Once the core assets are in place, system building becomes a matter of 18 | 19 | - Accessing the appropriate assets in the core asset base 20 | 21 | - Exercising the variation points to configure them as required for the system 22 | 23 | being built 24 | 25 | - Assembling that system 26 | 27 | In the ideal case, this can be done automatically. Additional software developed for an individual product, if needed at all, tends to account for a small fraction of the total software. Integration and testing replace design and coding as the pre- dominant activities. 28 | 29 | Product lines are nothing new in manufacturing. Many historians trace the con- cept to Eli Whitney’s use of interchangeable parts to build rifles in the early 1800s, but earlier examples also exist. Today, there are hundreds of examples in manufacturing: think of the products of companies like General Motors, Toy- ota, Boeing, Airbus, Dell, even McDonald’s, and the portfolio of similar products that each one produces. Each company exploits commonality in different ways. Boeing, for example, developed the 757 and 767 in tandem, and the parts lists of these two very different aircraft overlap by about 60 percent. 30 | 31 | The improvements in cost, time to market, and productivity that come with a suc- cessful software product line can be breathtaking. Consider: 32 | 33 | - Nokia credits the software product line approach with giving it flexibility to bring over a dozen phones to market each year, as opposed to the three or so it could manage before, all with an unprecedented variety of features. 34 | - Cummins, Inc., was able to reduce the time it takes to produce the software for a diesel engine from about a year to about a week. 35 | - Hewlett-Packard builds products using one-quarter of the staff, in one-third of the time, and with one twenty-fifth the number of defects, compared with software built before the advent of software product line engineering. 36 | - Deutsche Bank estimates $4 million in savings per year realized from building its global transaction and settlement software as a product line. 37 | - Philips reports reduced faults during integration in its high-end television portfolio by adopting the product line approach. Product diversity used to be one of the top three concerns of their architects. Now it doesn’t even make the list of concerns at all; the product line approach has taken software development off the critical path—the software no longer determines the delivery date of the product. 38 | 39 | - With a product line of satellite ground control systems it commissioned, the 40 | 41 | U.S. National Reconnaissance Office reported the first product requiring 10 percent the expected number of developers and having one-tenth the ex- pected number of defects. 42 | 43 | - In Philips’s medical systems product line, the software product line ap- proach has cut both software defects and time to market by more than half. 44 | 45 | Creating a successful product line depends on a coordinated strategy involving software engineering, technical management, and organization management. Be- cause this is a book on software architecture, we focus on the architectural as- pects of software product lines, but all aspects must work together in order for an organization to successfully create a product line. 46 | 47 | 48 | 49 | **25.1 an Example of Product line Variability** 50 | 51 | The following example will help us illustrate the concept of product line vari- ability. In a product line of software to support U.S. bank loan offices, suppose we have a software module that calculates what a customer owes in the current month. For 18 of the 21 products in our product line, this module is completely adequate. However, our company is about to enter the market in the state of Del- aware, which has certain laws that affect what a customer can owe. For the three products we plan to sell in Delaware, we need a module that differs from the “standard” module. Analysis shows that the difference will affect about 250 lines of source code in our 8,000-line module. 52 | 53 | To build one of the Delaware products, what do we do? An obvious op- tion is to copy the module, change the 250 or so lines, and use the new version in the three products. This practice is called “clone-and-own”—the new projects “clone” the module, change it, and then “own” the new version. Most companies, when faced with this situation, resort to clone-and-own. It’s expedient in that it provides a quick start to a new product, but it comes with a substantial cost down the road. 54 | 55 | The problem with clone-and-own is that it doesn’t scale. Suppose each of our 21 products comprises roughly 100 modules. If each module is allowed to diverge for each product, that’s potentially 2,100 modules that the maintenance staff has to deal with, each one spiraling off on its own separate maintenance trajectory based on the needs of the lone project each version is used in. Many companies’ growth in a market is limited—brought to a halt, in fact—by their in- ability to staff the maintenance of so many separate versions of so many different assets composing the products in their portfolio. An organization fielding several versions of several products finds itself dealing with a staggeringly complex code base. The strain begins to show when a systematic change needs to be made to all of the products—for example, to add a new feature, or migrate to a new platform, or make the user interface work in a different language. Because each version of each component used in each product has been allowed to evolve separately, now suddenly making a systematic change becomes prohibitively expensive (and only gets worse each time a new product is added—the labor involved grows as the *square* of the number of products). It only takes a few such portfolio-wide changes before organizations feel that they’ve hit a wall of complexity and expense. 56 | 57 | So much for clone-and-own. What else can we do? Instead of allowing up to 21 versions of each module, we would much rather find a way to take advantage of the fact that these nearly identical modules vary only in small, well-defined ways. To take advantage of their similarities, we introduce a *variation mechanism* into the module. (Variation mechanisms are often realized as tactics, such as the “defer binding” set of tactics described in Chapter 7.) This variation mechanism will let us maintain a single module that can adapt to the range of variations in the applications (in our example, the 21 banking products) that it has to support. If we plan to market our products in states that, like Delaware, have their own laws affecting what a customer owes, we may need to support additional varia- tions of the module. So our variation mechanism should be able to accommodate those possibilities as well. 58 | 59 | The payoff for this up-front planning is that an asset used in any of the prod- ucts exists as a *single* version that (through the exercising of built-in variation mechanisms) works for all of the products in the product line. And now, mak- ing a portfolio-wide change merely consists of changing the core assets that are affected. Because all future versions of all products use the same core assets, changing the core asset base has the effect of changing all of the products in the organization’s portfolio. 60 | 61 | 62 | 63 | **25.2 What Makes a Software Product line Work?** 64 | 65 | What makes product lines succeed is that the commonalities shared by the prod- ucts can be exploited through reuse to achieve production economies. The poten- tial for reuse is broad and far-ranging, including the following: 66 | 67 | - *Requirements*. Most of the requirements are common with those of earlier systems and so can be reused. In fact, many organizations simply maintain a single set of requirements that apply across the entire family as a core asset; the requirements for a particular system are then written as “delta” documents off the full set. In any case, most of the effort consumed by re- quirements analysis is saved from system to system. 68 | 69 | - *Architectural design*. An architecture for a software system represents a large investment of time from the organization’s most talented engineers. As we have seen, the quality goals for a system—performance, reliability, modifiability, and so forth—are largely promoted or inhibited once the architecture is in place. If the architecture is wrong, the system cannot be saved. For a new product, however, this most important design step is al- 70 | 71 | ready done and need not be repeated. 72 | 73 | - *Software elements*. Software elements are applicable across individual 74 | 75 | products. Element reuse includes the (often difficult) initial design work. Design successes are captured and reused; design dead ends are avoided, not repeated. This includes design of each element’s interface, its docu- mentation, its test plans and procedures, and any models (such as perfor- mance models) used to predict or measure its behavior. One reusable set of elements is the system’s user interface, which represents an enormous and vital set of design decisions. And as a result of this interface reuse, products in a product line usually enjoy the same look and feel as each other, an ad- vantage in the marketplace. 76 | 77 | - *Modeling and analysis*. Performance models, schedulability analysis, dis- tributed system issues (such as proving the absence of deadlock), allocation of processes to processors, fault tolerance schemes, and network load poli- cies all carry over from product to product. Companies that build real-time distributed systems report that one of the major headaches associated with production has all but vanished. When they field a new product in their product line, they have high confidence that the timing problems have been worked out and that the bugs associated with distributed computing— synchronization, network loading, and absence of deadlock—have been eliminated. 78 | 79 | - *Testing*. Test plans, test processes, test cases, test data, test harnesses, and the communication paths required to report and fix problems are already in place. 80 | 81 | - *Project planning artifacts*. Budgeting and scheduling are more predictable because experience is a high-fidelity indicator of future performance. Work breakdown structures need not be invented each time. Teams, team size, and team composition are all easily determined. 82 | 83 | All of these represent valuable core assets, each of which can be imbued with its own variation points that can be exercised to build a product. We’ll look at architectural variation points later in this chapter, but for now imagine that any artifact represented by text can consist of text blocks that are exposed or hidden for a particular product. Thus, the artifact that is maintained in the core asset base represents a superset of any version that will be produced for a product. 84 | 85 | Artifact reuse in turn enables reuse of knowledge: 86 | 87 | ■ *Processes, methods, and tools*. Configuration control procedures and fa- cilities, documentation plans and approval processes, tool environments, system generation and distribution procedures, coding standards, and many other day-to-day engineering support activities can all be carried over from product to product. The software development process is in place and has been used before. -------------------------------------------------------------------------------- /Software-Architecture/8. product-line.md: -------------------------------------------------------------------------------- 1 | # 软件产品线 2 | 3 | Software Product Lines 4 | 5 | 什么是产品线? 6 | 7 | ``` 8 | 软件产品线是指具有⼀组可管理的公共特性的软件密集性系统的合集,这些系统满足特定的 9 | 市场需求或任务需求,并且按预定义的方式从⼀一个公共的核⼼资产集开发得到。 10 | ``` 11 | 12 | Products=Custom Assets+Core Assets 13 | 14 | Core Assets: 15 | 16 | 在 SPL 中被⼤量产品复⽤用 提供领域内的知识和经验,满足领域需求 实现SPL范围中的需求 17 | 提供⼤量variation points以适应不不同特性 18 | 19 | Custom Assets: 关于特定的产品 集成产品所需的core assets 满足⽤户特定的需求 实现SPL范围外的需求 20 | 21 | 将core assets中的可变化的部分实例例化 22 | SPL Engineering = Core Asset Development(Domain Engineering)+Product 23 | 24 | Development(Application Engineering) 25 | 26 | 为什什么要进⾏行行**SPL**开发? 节约成本 27 | 简单 将项⽬工作转变为产品特征 提⾼产品质量 更容易适应市场 28 | 29 | **Reuse & Variation** 30 | 31 | 复⽤用: 32 | 33 | 代码复⽤用很容易易,已经是开发者想要的了了,不不再仅仅是almost,所以复制之后不不⽤用再修改 reuse机制的核⼼心是: 34 | find code:源码控制⼯工具或查找库/API 35 | understand code:在workspace中阅读源码或阅读库/API⽂文档 36 | 37 | invoke code 38 | 39 | 可变性: 40 | 41 | ``` 42 | 为了了最⼤大化复⽤用率,使得代码是可变的 43 | 适⽤用于⼤大型系统,让代码更更加灵活,现在设计,未来复⽤用 44 | ``` 45 | 46 | 应该⽀支持多少的可变性?—由产品线范围 Product Line Scope 定义 产品线范围 PLS,Product Line Scope 是组成产品线或能被产品线包括的产品的描述 47 | 48 | 如何实现可变性?—设计产品线架构、使⽤用reuse and viriation mechanisms **PLA**(**Product Line Architecture**) 49 | 定义公⽤用的功能和可改变的功能 50 | 识别并⽀支持variation points 51 | 52 | 可变性机制 **Variation Mechanisms 6**种变化的形式? **Forms of Variation** 包括或省略略元素 53 | 改变元素的数量量 54 | 不不同的实现满⾜足⼀一个统⼀一的接⼝口 参数化。让客户从预先设定好的功能范围中选择 “Hook”接⼝口。客户提供变化的功能 反射。在程序运⾏行行过程中感知外部的变化,进⾏行行⾃自身调节 55 | 56 | **3**个变化的位置?**Software entity varied** 架构级别 57 | 设计级别 58 | ⽂文件级别 59 | 60 | **5**个变化的时间?**Binding time** Coding-time — workspace配置 Compile-time — 编译器器设置 Link-time — 连接选项 Initialization-time —配置⽂文件 Run-time —⽤用户/管理理员等定制化 61 | 62 | e.g.. OO继承:满⾜足接⼝口*设计级别*coding—time 63 | 64 | 产品线⽅方法 **Product line approach 3**个基本活动 **essential activities** 核⼼心资产开发 65 | 产品开发 66 | 67 | 管理理 68 | 69 | **29**个实践领域 **Practice Areas** (分为以下三类) 软件⼯工程 70 | 技术管理理 71 | 组织管理理 72 | 73 | **22**个实践模式 **Practice Patterns** Curriculum、Essential Coverage 、Factory、Product Parts 、Each Asset 、Cold Start Pattern 74 | 75 | pattern template: 76 | 77 | name、example、context、problem、solution static:实践领域的分组列列表 dynamics:实践领域之间的关系 application、variants、consequences 78 | 79 | 【考题】软件产品线架构 **vs** 单个产品架构 80 | 81 | 软件产品线是指具有⼀组可管理理的公共特性的软件密集性系统的合集,这些系统满足特定的 市场需求或任务需 82 | 83 | 求,并且按预定义的⽅方式从⼀一个公共的核⼼心资产集开发得到。 84 | 85 | 首先,与单个产品架构相⽐比,产品线中的产品分为custom assets 和 core assets 两部分 86 | 87 | 所以它们的主要不同在于关注点转移: 从单独的产品到产品线的项目暗示了一个策略: 从特定的项目开发到特定业务领域产品的愿景产品线关注产品的特征,⽽单个产品架构更关注项目本身。 88 | 此外,产品线具有可重用和可变性两大特征。 89 | 产品线中的重⽤与单个产品架构中代码的重用相比,还包括了需求、业务等,几乎已经是开发者想要的了,⽽不用像单个产品架构中那样复制之后再修改。 90 | 91 | 产品线架构还拥有可变性的特点,在如单个产品架构定义正常功能之外,还定义了可改变的 功能,可以识别并⽀支持variation points。 92 | 93 | 总的来说,软件生产线架构与单个产品架构相比,可以减少成本、快速上市、减少风险、提高质量,更容易易适应市场 -------------------------------------------------------------------------------- /Software-Architecture/8. (1) product-line.md: -------------------------------------------------------------------------------- 1 | # 软件产品线 2 | 3 | ## 一. 产品线基本 4 | 5 | 6 | 7 | ### 1. 概述和概念 8 | 9 | #### 1. 什么是软件产品线 10 | 11 | * Lots of different (but related) Products 12 | 13 | * Assembled from reused Core Assets 14 | 15 | **Products = Custom Assets + Core Assets** 16 | 17 | A software product line is a set of software intensive systems **sharing a common, managed set of features** that satisfy the specific needs of a particular market segment or mission and that are **developed from a common set of core assets** in a prescribed way. 18 | 19 | 20 | 21 | ##### Core Assets 22 | – Reused by many (or all) products in the SPL 23 | – Embody domain knowledge/expertise 24 | – Provide variation points for variable features 25 | – Implements requirements within the SPL scope 26 | 27 | 28 | 29 | ##### Custom Assets 30 | – Specific to a particular product 31 | – Meet customer-specific requirements 32 | – Can also implement requirements out of the SPL scope 33 | – Integrate core assets required for the product 34 | – Instantiate variation points provided by core assets 35 | 36 | #### 2. 产品线优点 37 | 38 | Economies of Scale 39 | – Spread core asset costs over more products 40 | – Especially Design, Coding, Unit Test costs 41 | 42 | 43 | 44 | Simplicity – it’s easier to: 45 | – See what assets are “core” for the business 46 | – See how different products differ 47 | – Upgrade customised products with new “core” 48 | 49 | 50 | 51 | Turn Project Work into Product Features 52 | – Separate custom assets out from a product 53 | – Re-use them as “core” assets in other products 54 | 55 | 56 | 57 | Improve Product Quality 58 | – Core asset bug fixes are done once 59 | – Core asset bug fixes are more easily shared 60 | – Products have different patterns of use 61 | • Exposes different bugs – improves overall quality 62 | 63 | 64 | 65 | • Improve Time-to-Market 66 | – For a new product, don’t need to re-develop the core 67 | – Approach the dream of “Lego” components & products 68 | 69 | 70 | 71 | 例如还可以从代码行的角度去分析(但是这个例子把传统的看做成了完全不动,还是有一点不是很理解) 72 | 73 | #### 3. 重用 和 变更 74 | 75 | Code reuse is easy! 76 | – (If it already does exactly what you want!) 77 | – To reuse code, a developer just needs to: 78 | 79 | 1. find it 80 | 2. understand it 81 | 3. invoke it 82 | 83 | 84 | 85 | Code that’s “almost what you want”… 86 | – …is normally completely useless 87 | – Often can only reuse it by “cut and paste” 88 | • a.k.a. “clone and own” 89 | • And only if you have the source code too 90 | 91 | 92 | 93 | • Identify and Support “Variation Points” 94 | – Lists all allowed variation 95 | – Architectural interfaces for variation 96 | – Specifies mechanisms to instantiate variation points 97 | – (See variation mechanisms later) 98 | 99 | 100 | 101 | 102 | 103 | 下面是重要的 104 | 105 | Reuse Mechanisms 106 | 107 | Variation Mechanisms 108 | – Level of variation 109 | – Binding time 110 | 111 | 112 | 113 | 114 | 115 | 设计点和变化维度 116 | 117 | #### 1. FORMS OF VARIATION 118 | 119 | – Include or omit elements 120 | – Variable number of each element 121 | – Interface Satisfaction 122 | • Different implementations satisfying a uniform interface 123 | • Sub-typing (and OO inheritance) 124 | • Vary behaviour without varying integration structure 125 | – Parameterisation 126 | • Let clients choose from a pre-specified range of functionality 127 | – “Hook” interfaces 128 | • Let client software supply the variant functionality 129 | – Reflection 130 | • Make elements discover and react to their (variable) context 131 | 132 | #### 2. SOFTWARE ENTITY VARIED 133 | 134 | Architecture level – High-level abstract structures 135 | – e.g. frameworks, deployment configurations, schemas, etc 136 | • Design level – Lower-level abstract structures 137 | – e.g. classes, interfaces, methods, etc 138 | • File level – low-level concrete source structures 139 | – e.g. directory hierarchies, files, lines of source code, etc 140 | 141 | #### 3. BINDING TIME 142 | 143 | Coding-time – when you create a coding workspace 144 | • Compile-time – when you build object code 145 | • Link-time – when you create your application 146 | • Initialization-time – when your application starts 147 | • Run-time – while your application is running 148 | 149 | 150 | 151 | SEI 产品线方法 152 | 153 | #### 1. 3 个关键活动 154 | 155 | 1. Core Asset Development 156 | 2. Product Development 157 | 3. Management 158 | 159 | #### 2. 29个实践领域 160 | 161 | ##### 1. Software Engineering 162 | 163 | – Architecture Definition 164 | – Architecture Evaluation 165 | – Component Development 166 | – COTS Utilization 167 | – Mining Existing Assets 168 | – Requirements Engineering 169 | – Software System Integration 170 | – Testing 171 | – Understanding Relevant Domains 172 | 173 | ##### 2. Technical Management 174 | 175 | – Configuration Management 176 | – Data Collection, Metrics, and Tracking 177 | – Make/Buy/Mine/Commission Analysis 178 | – Process Definition 179 | – Scoping 180 | – Technical Planning 181 | – Technical Risk Management 182 | – Tool Support 183 | 184 | ##### 3. Organizational Management 185 | 186 | – Building a Business Case 187 | – Customer Interface Management 188 | – Developing an Acquisition Strategy 189 | – Funding 190 | – Launching and Institutionalizing 191 | – Market Analysis 192 | – Operations 193 | – Organizational Planning 194 | – Organizational Risk Management 195 | – Structuring the Organization 196 | – Technology Forecasting 197 | – Training 198 | 199 | #### 3. 实践模式 200 | 201 | • Assembly Line 202 | • Cold Start 203 | • Curriculum 204 | • Each Asset 205 | • Essentials Coverage 206 | • Factory 207 | • In Motion 208 | • Monitor 209 | • Process 210 | • Product Builder 211 | • Product Parts 212 | • What to Build 213 | 214 | ###### 模式描述模板 215 | 216 | • Name 217 | • Example – scenarios to illustrate context & problem 218 | • Context – org. situations when it may be relevant 219 | • Problem – what part of SPL effort has to be done 220 | • Solution – the basis for grouping the practice areas 221 | • Static – grouped lists of practice areas 222 | • Dynamics – relationships between the practice areas 223 | • Application – guidelines for applying the pattern 224 | • Variants – specialisations or modifications 225 | • Consequences – benefits and any limitations 226 | 227 | 228 | 229 | 230 | 231 | 1. What distinguishes an architecture for a software product line from an architecture for a single product? 232 | 233 | 234 | 235 | 软件产品线是指具有⼀组可管理理的公共特性的软件密集性系统的合集,这些系统满足特定的 市场需求或任务需求,并且按预定义的⽅方式从⼀一个公共的核⼼心资产集开发得到。 236 | 237 | 238 | 239 | 首先,与单个产品架构相⽐比,产品线中的产品分为custom assets 和 core assets 两部分 240 | 241 | 所以它们的主要不同在于关注点转移: 从单独的产品到产品线的项目暗示了一个策略: 从特定的项目开发到特定业务领域产品的愿景产品线关注产品的特征,⽽单个产品架构更关注项目本身。 242 | 243 | 244 | 245 | 此外,产品线具有可重用和可变性两大特征。 246 | 产品线中的重⽤与单个产品架构中代码的重用相比,还包括了需求、业务等,几乎已经是开发者想要的了,⽽不用像单个产品架构中那样复制之后再修改。 247 | 248 | 产品线架构还拥有可变性的特点,在如单个产品架构定义正常功能之外,还定义了可改变的功能,可以识别并支持 variation points。 249 | 250 | 总的来说,软件生产线架构与单个产品架构相比,可以减少成本、快速上市、减少风险、提高质量,更容易适应市场。 251 | 252 | 253 | 254 | ## 林宇超整理部分 255 | 256 | 1、什么是Product Line? 257 | 258 | 1)定义:软件产品线是一个共享一个共有的、管理好的特性集合的软件密集型系统, 这个特性集是满足了一个特定 市场划分需求或任务,并且是从一组预先定义好的共有的核心集开发的。 259 | 260 | 2)有很多产品组成的,有一定共性。把一个产品分成两部分:core assets + custom assets,共享core assets 261 | 262 | 3)核心资产core asset : 被 SPL 中许多(或全部)的产品复用、包含了领域知识、为变化的特性提供了变化点 263 | 264 | (variation points)、在 SPL 的范围内实现需求。 265 | 4)自定义资产(custom assets):针对一个具体的产品、满足了自定义特点的需求、集成了产品需要的核心资产、实例 266 | 267 | 化了核心资产的变化点 268 | 269 | 5)特点:通常有大量变化点、为大规模的重用设计(不适合小型重用)、使用系统层次上的复用(不适用于单个系统内的 270 | 271 | 重用) 272 | 273 | 2、软件产品线如何开发的? 274 | 275 | 为什么使用 SPL(基本上都是重用的优点) 276 | 277 | 1)大规模下更经济。将核心资产的成本分摊到了更多的产品中。特别是设计、编码和单元测试。 278 | 279 | 2)更简单。更容易发现哪些资产是商业的核心资产、不同产品之间是如何不同的、通过新的核心资产更新自定义产 品 280 | 281 | 3)为项目工作带来产品特性。从产品中划分出自定义资产,在其他产品中重用这些资产。 282 | 283 | 4)提高产品质量。核心资产的bug只用修改一次。核心资产的bug修复会被多个项目共享。产品可以有不同的使用模 284 | 285 | 式。 286 | 287 | 5)提高了产品的开发速度。对于一个新产品,不用再去开发核心资产。 288 | 289 | 3、重用和变化(Reuse & Variation) 290 | 291 | 代码复用是容易的。 292 | 293 | ``` 294 | 变化是大规模复用的关键点,要使代码更易变化,现在设计,将来复用。因此要用产品线来决定重用多少、如何重 295 | 用。 296 | ``` 297 | 298 | 4、 产品线范围(PLS) 299 | 300 | 定义:产品线范围是用来描述可能构成产品线的产品或产品线能够包含的产品。 公司关注的只是一个特定的领域。产 品线范围是用来限定这种关注的。 301 | 302 | 5、产品线架构(PLA) 303 | 304 | 为PLS里定义的变化提供支持。PLS规定了一些列的产品和功能,PLA 为怎么去处理这些变化做出了实际的决策 305 | 306 | SPL 是在重用一系列架构基础 
 307 | 308 | PLA 可以看做是SPL的核心资产 
 309 | 310 | PLA 定义了统一(公用)的功能和变化的功能。 
 311 | 312 | 识别和支持变化点。 
 313 | 314 | 6、产品线生产计划 315 | 316 | 定义:生产计划描述了产品是怎么通过核心资产生产出来的。 
 317 | 318 | Product=Core Asset(s) + Custom Asset(s),SPL 生产计划类似于其中的“+”是怎么实施的。 319 | 320 | 产品线工程框架(SPL Engineering Framework) 321 | 322 | 领域工程(Domain Engineering):领域工程是 SPL 中识别和定义 SPL 中的公共点和变化点的过程 323 | 324 | 制品:Product Roadmap、Domain Variability Model、Domain Requirements、Domain Architecture、Domain Realisation Artefacts、 Domain Test Artefacts 325 | 326 | 应用工程(Application Engineering):应用工程是 SPL 中通过重用领域制品和应用产品线的变化来构造应用的过程 制品:Application Variability Model、Application Requirements、Application、Architecture、Application 327 | 328 | Realisation Artefacts、Application Test Artefacts 329 | 330 | 17. Product Line Architecture 331 | 332 | Reuse: find, understand, and use (invoke) Variation: forms of variation * software entity varied * binding time Architecture: variation points 333 | 334 | 335 | 336 | Reuse机制: 发现、理解、使用 337 | 338 | Variation机制: Variation是通过Variation的形式、Variation的实体、和Variation的时间来定义的(3维的一个东西) Variation的形式(Form): 6种 339 | 340 | 1. 包含或忽略元素。(元素种类) 341 | 342 | 2. 同一个元素的不同数量。(元素数量) 343 | 344 | 3. 参数化。让产品从一个预定义好的功能中选择。 345 | 346 | 4. Interface Satisfaction 同一个接口的不同实现、子类、改变行为而不改变接口 347 | 5. 钩子接口。让产品自己提供变化的功能。 348 | 349 | 6. 反射。让元素发现其所在的上下文并作出反应。 350 | 351 | Variation的实体(Entity): 3种 352 | 353 | 1. 架构层次:高层的抽象结构。框架、发布配置、系统结构。 354 | 2. . 设计层次:中层的抽象结构。类、接口、方法。 355 | 3. 文件层次:底层的具体结构。项目结构、文件、代码 356 | 357 | Variation的时间: 5个 358 | 359 | 1. 编码期。当你创建了一个代码工作区。工作区配置(IDE、版本控制工具) 360 | 361 | 2. 编译期。当你生成你的目标代码。编译配置、宏、文件替换(构建脚本) 362 | 363 | 3. 连接期。当你创建你的应用。连接目标,二进制替换(构建脚本) 364 | 365 | 4. 初始化。当你的应用开始工作。配置文件,注册表设置(已经设计好和编码好的初始化信息) 366 | 367 | 5. 运行时。在你的应用运行期间。用户、管理员、供应商定制(supplier customization)(设计和编码好的界面) 368 | 369 | 例子: 370 | 源代码模块:包括或忽略元素×文件层次×编码期 面对对象继承结构:Interface satisfaction×设计层次×编码期 371 | 372 | \18. SPL Practice Areas and Patterns 373 | 374 | 29 practice areas and 22 patterns 375 | 376 | 1、SEI产品线方法 377 | 378 | 1)3 个必须的活动: 核心资产开发(Core Asset Development)、产品开发(Product Development)、 管理 (Management) 
 379 | 380 | 2) 29 个Practice Areas: 内部通过不同的方式关联;均有限制;互相结合实现了 SPL 开发和商业价值 
 381 | 382 | \1. 软件工程:架构定义、架构评估、组件开发、测试等 2. 技术管理:配置管理、数据收集、技术风险管理等 3. 组织管理:建立商业用例、市场分析、培训等。 
 383 | 384 | 3) 12(22)个Practice Patterns: 展示了实践领域是如何结合、怎么结合来达到一系列不同的 
 385 | 目标、Assembly line、Cold Start、Curriculum、Each Asset、Essentials Coverage、Factory、In Motion、 386 | 387 | Process、Product Builder、Product Parts、What to Build 架构的定义:定义了软件系统的结构:组件、外部可见行为、之间关系 SPL特性:有可重用性和可修改性;变化不只发生在代码上;更频繁的整合 具体经验:ADD、架构模式、质量属性workshop、变化机制.. 架构评估:确实符合功能需求、满足质量属性、可以在多个时间点做这个 2、SPL开发和变更控制 388 | 389 | 核心资产的变更会造成所有产品的变更 
 390 | 391 | 难题:负载的配置识别、不同产品发布的约束、为变化点进行变更、产品线退化 
 392 | 393 | change control 配置管理=版本控制+变化控制 394 | 395 | 什么时候改变架构?proactive、reactive、retroactive 396 | 397 | 解决方法:SCM、CoreAssetChangeControlBoard(CCB)、SPLRoadMap、Higher-Quality 
Core Assets、Emergency “Fake” Core Changes in Custom Assets 
 398 | 399 | 400 | 401 | -------------------------------------------------------------------------------- /Software-Architecture/9. mirco_service.md: -------------------------------------------------------------------------------- 1 | # 微服务架构 2 | 3 | 4 | 5 | ## 面向服务架构 6 | 7 | 是一个分布式组件的集合,这些组件为其他组件提供服务,或者消费其他组件所提供的服务,而无需知道其它组件的实现细节。 8 | 9 | ### 企业服务总线 (ESB) 10 | 11 | 为服务间的相互调用提供环境支持,路由服务间的消息,并对消息和数据进行必要的转换。 12 | 13 | ### 服务编排引擎 14 | 15 | 可以根据预先定义的脚本对服务消费者与服务提供者之间进行指挥。 16 | 17 | 18 | 19 | ### 特点 20 | 21 | 1. 自身高内聚性,服务间松耦合,最小化开发维护中的相互影响 22 | 2. 良好的互操作性,符合开放标准 23 | 3. 模组化,高重用性 24 | 4. 服务动态识别,注册,调用 25 | 5. 系统复杂性提高 26 | 6. 难以测试验证 27 | 7. 各独立服务的演化不可控 28 | 8. 中间件易成性能瓶颈 29 | 30 | ### 面向服务架构实现原则 31 | 32 | 1. 服务解耦 33 | 2. 服务契约 34 | 3. 服务封装 35 | 4. 服务重用 36 | 5. 服务组合 37 | 6. 服务自恰 38 | 7. 服务无状态 39 | 40 | 41 | 42 | ### 优缺点 43 | 44 | #### 优点 45 | 46 | 1. 服务重用性 47 | 2. 易维护性 48 | 3. 高可靠性 49 | 4. 高扩展和可用性 50 | 5. 软件质量提升 51 | 6. 平台无关 52 | 7. 提升效率 53 | 54 | #### 缺点 55 | 56 | 1. 过分使用 ESB 57 | 58 | 2. 使用基于 SOAP 协议的 WS 59 | 60 | 3. 使用形式化的方法管理 : 管理复杂度高 61 | 62 | 4. 需要使用可靠的ESB 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ## 微服务架构 71 | 72 | 微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制,这些服务围绕业务能力构建并课通过自动部署机制独立部署。 73 | 74 | 75 | 76 | 微服务架构的本质仍然是一种分布式架构,也是面向服务架构的一种。 77 | 78 | 79 | 80 | ### 微服务架构的特点 81 | 82 | 1. 通过服务组件化 83 | 2. 围绕业务能力组织 84 | 3. 内聚和解耦 85 | 4. 去中心化 86 | 5. 基础设施自动化 Web Services 概念 87 | 6. 服务设计 高可用性,变更与演化 88 | 89 | 90 | 91 | ### 优缺点 92 | 93 | #### 优点 94 | 95 | 1. 简单 96 | 2. 团队独立性 97 | 3. 松耦合 98 | 4. 平台无关性 99 | 5. 通信协议轻量级 100 | 101 | #### 缺点 102 | 103 | 1. 运维成本过高 104 | 2. 分布式系统的复杂性 105 | 3. 异步,消息与并行方式让开发门槛变高 106 | 4. 分布式系统的复杂性也会让系统的测试变得复杂 107 | 108 | 109 | 110 | 核心模式 111 | 112 | 1.服务注册与发现 113 | 114 | 1. 启动时注册到服务发现组件 115 | 116 | 2. 消费者可以从服务发现组建找到提供者的网络地址和接口 117 | 118 | 3. 服务与服务发现组件利用一定机制通讯,否则注销 119 | 4. 服务变更会自动重新注册 120 | 121 | 122 | 123 | 124 | 125 | 2. API网关,单一入口点,针对不同客户端提供不同API 126 | 127 | 128 | 129 | 1. 确保客户端不关心服务划分方式 130 | 131 | 2. 客户端不受服务实例位置影响 132 | 133 | 3. 提供最优API 134 | 135 | 4. 降低请求往返次数 136 | 137 | 5. 简化客户端 138 | 139 | 140 | 141 | 142 | 143 | 3. 熔断器(模式) 144 | 145 | 1. 防止程序不断尝试可能会失败的操作 146 | 2. 使程序诊断错误是否修正,进而再调用 147 | 3. 状态: 148 | 149 | ``` 150 | 闭合:请求能够调用 151 | 断开:请求会报错 152 | 半断开:一定数量可调用,调用成功则闭合,不成功则断开 153 | ``` 154 | 155 | 4. 实现 156 | 157 | ### 介绍 158 | 159 | **微服务** (Microservices) 是一种 软件架构风格,它是以专注于单一责任与功能的小型功能区块 (Small Building Blocks) 为基础,利用模块化的方式组合出复杂的大型应用程序,各功能区块使用与语言无关 (Language-Independent/Language agnostic) 的 API 集相互通信。 160 | 161 | 微服务的起源是由 Peter Rodgers 博士于 2005 年度云计算博览会提出的微 Web 服务 (Micro-Web-Service) 开始,Juval Löwy 则是与他有类似的前导想法,将类别变成细粒服务 (granular services),以作为 [Microsoft](https://zh.wikipedia.org/wiki/Microsoft) 下一阶段的软件架构,其核心想法是让服务是由类似 Unix 管道的访问方式使用,而且复杂的服务背后是使用简单 [URI](https://zh.wikipedia.org/wiki/URI) 来开放接口,任何服务,任何细粒都能被开放 (exposed)。这个设计在 HP 的实验室被实现,具有改变复杂软件系统的强大力量。 162 | 163 | 2014年,[Martin Fowler](https://zh.wikipedia.org/wiki/Martin_Fowler) 与 [James Lewis](https://zh.wikipedia.org/w/index.php?title=James_Lewis&action=edit&redlink=1) 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的行程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理 (例如 [Docker](https://zh.wikipedia.org/wiki/Docker)) 能力,服务可以用不同的编程语言与数据库等组件实现[[1\]](https://zh.wikipedia.org/wiki/%E5%BE%AE%E6%9C%8D%E5%8B%99#cite_note-1)。 164 | 165 | 166 | 167 | ### 概念 168 | 169 | 微服务是一种以业务功能为主的服务设计概念,每一个服务都具有自主运行的业务功能,对外开放不受语言限制的 API (最常用的是 HTTP),应用程序则是由一个或多个微服务组成。 170 | 171 | 微服务的另一个对比是**单体式应用程序**。单体式应用表示一个应用程序内包含了所有需要的业务功能,并且使用像[主从式架构](https://zh.wikipedia.org/wiki/%E4%B8%BB%E5%BE%9E%E5%BC%8F%E6%9E%B6%E6%A7%8B)(Client/Server) 或是[多层次架构](https://zh.wikipedia.org/w/index.php?title=%E5%A4%9A%E5%B1%A4%E6%AC%A1%E6%9E%B6%E6%A7%8B&action=edit&redlink=1) (N-tier) 实现,虽然它也是能以分布式应用程序来实现,但是在单体式应用内,每一个业务功能是不可分割的。若要对单体式应用进行扩展则必须将**整个**应用程序都放到新的运算资源(如:虚拟机) 内,但事实上应用程序中最吃资源、需要运算资源的仅有某个业务部分(例如跑分析报表或是数学算法分析),但因为单体式应用无法分割该部分,因此无形中会有大量的资源浪费的现象。 172 | 173 | 微服务运用了以业务功能的设计概念,应用程序在设计时就能先以业务功能或流程设计先行分割,将各个业务功能都独立实现成一个能自主运行的个体服务,然后再利用相同的协议将所有应用程序需要的服务都组合起来,形成一个应用程序。若需要针对特定业务功能进行扩展时,只要对该业务功能的服务进行扩展就好,不需要整个应用程序都扩展,同时,由于微服务是以业务功能导向的实现,因此不会受到应用程序的干扰,微服务的管理员可以视运算资源的需要来配置微服务到不同的运算资源内,或是布建新的运算资源并将它配置进去。 174 | 175 | 虽然使用一般的[服务器虚拟化](https://zh.wikipedia.org/w/index.php?title=%E4%BC%BA%E6%9C%8D%E5%99%A8%E8%99%9B%E6%93%AC%E5%8C%96&action=edit&redlink=1)技术就能应用于微服务的管理,但容器技术 (Container Technology) 如 [Docker](https://zh.wikipedia.org/wiki/Docker) 会更加地适合发展微服务的运算资源管理技术。 176 | 177 | 178 | 179 | ### 规划 180 | 181 | 微服务的规划与**单体式应用程序**十分不同,微服务中每个服务都需要避免与其他服务有所牵连,且都要能够自主,并在其他服务发生错误时不受干扰。 182 | 183 | 184 | 185 | #### 数据库 186 | 187 | 微服务理念中有数个数据库的规划方式。 188 | 189 | - 每个服务都各有一个数据库,同属性的服务可共享同个数据库。 190 | - 所有服务都共享同个数据库,但是不同表格,并且不会跨域访问。 191 | - 每个服务都有自己的数据库,就算是同属性的服务也是,数据库并不会共享。 192 | 193 | 数据库并不会只存放该服务的数据,而是“**该服务所会用到的所有数据**”。更深层一点的举例:假设有个文章服务,而这个服务可能会需要判断用户的账号⋯⋯等。那么文章服务的数据库就可以放入用户的部分数据。此举是为了避免服务之间的相依性,避免文章服务调用用户服务。 194 | 195 | ####数据库的可弃性 196 | 197 | 实践微服务有许多的做法,但其中一种做法是将数据库作为**短期**的存储空间而不是存储长期的数据。这意味着数据库可以在离线时被清空。因为它们可以在上线时从事件存储中心恢复,因此也能以存储器缓存(如:[Redis](https://zh.wikipedia.org/wiki/Redis)) 作为数据库服务器。但这种做法需要将每个请求当作事件来进行广播。如此一来就可以从事件存储中心重播所有的事件来找回所有的数据。 198 | 199 | #### 沟通与事件广播 200 | 201 | NSQ 是一个消息队列系统、平台。在微服务中所扮演的角色是将消息、数据传递到其他服务。 此举是异步运行,所以不需要等到其他服务接收到消息就能够运行下一步。这种方式能够避免服务之间有所牵连、调用。 202 | 203 | 微服务中最重要的就是每个服务的独立与自主,因此服务与服务之间也**不应该**有所沟通。倘若真有沟通,也应采用异步沟通的方式来避免紧密的相依性问题。要达到此目的,则可用下列两种方式: 204 | 205 | #### 事件存储中心(Event Store 206 | 207 | 这可以让你在服务集群中广播事件,并且在每个服务中监听这些事件并作处理,这令服务之间没有紧密的相依性,而这些发生的事件都会被保存在事件存储中心里。这意味着当微服务重新上线、部署时可以重播(Replay)所有的事件。这也造就了微服务的数据库随时都可以被删除、摧毁,且不需要从其他服务中获取数据。 208 | 209 | #### 消息队列(Message Queue 210 | 211 | 这令你能够在服务集群中广播消息,并传递到每个服务中。具有这个功能的像是 NSQ 或是 [RabbitMQ](https://zh.wikipedia.org/wiki/RabbitMQ)。你能够在 A 服务上广播一个“创建新用户”的事件,这个事件可以顺便**带有**新用户的数据。而 B 服务可以**监听**这个事件并在接收到之后有所处理。这些过程都是异步处理的,这意味着 A 服务并不需要等到 B 服务处理完该事件后才能继续,而这也代表 A 服务无法获取 B 服务的处理结果。与事件存储中心近乎相似,但有所不同的是:消息队列并**不会**保存事件。一旦事件被消化(接收)后就会从队列中消失,这很适合用在像发送欢迎信件的时机。 212 | 213 | #### 服务探索 214 | 215 | 单个微服务在上线的时候,会向服务探索中心(如:Consul)注册自己的 IP 位置、服务内容,如此一来就不需要向每个微服务表明自己的 IP 位置,也就不用替每个微服务单独设置。当服务需要调用另一个服务的时候,会去询问服务探索中心该服务的 IP 位置为何,得到位置后即可直接向目标服务调用。 216 | 217 | 这么做的用意是可以统一集中所有服务的位置,就不会分散于每个微服务中,且服务探索中心可以每隔一段时间就向微服务进行健康检查(如透过:TCP 调用、HTTP 调用、Ping),倘若该服务在时间内没有回应,则将其从服务中心移除,避免其他微服务对一个无回应的服务进行调用。 218 | 219 | 220 | 221 | ### 内容 222 | 223 | 一个微服务框架的应用程序有下列特性: 224 | 225 | - 每个服务都容易被取代。 226 | - 服务是以能力来组织的,例如用户界面、前端、推荐系统、账单或是物流等。 227 | - 由于功能被拆成多个服务,因此可以由不同的编程语言、数据库实现。 228 | - 架构是对称而非分层(即生产者与消费者的关系)。 229 | 230 | 一个微服务框架: 231 | 232 | - 适用于具持续交付 (Continuous Delivery) 的软件开发流程。 233 | - 与[服务导向架构](https://zh.wikipedia.org/wiki/%E6%9C%8D%E5%8B%99%E5%B0%8E%E5%90%91%E6%9E%B6%E6%A7%8B) (Service-Oriented Architecture) 不同,后者是集成各种业务的应用程序,但微服务只属于一个应用程序。 -------------------------------------------------------------------------------- /Software-Architecture/README.md: -------------------------------------------------------------------------------- 1 | ## 课程重点 2 | 3 | 1. 软件体系结构的基本概念 4 | 2. 软件质量属性相关 5 | 3. 软件架构模式 6 | 4. 软件架构设计过程 7 | 5. 设计模式 8 | 6. 软件架构文档化 9 | 7. 软件架构评估 10 | 8. 软件产品线 11 | 9. 微服务架构 12 | 13 | 14 | 15 | ## Summary 中的点 16 | 17 | #### 1. Software Architecture in General 18 | 19 | 1. What is software architecture? (Structure, Elements, Relationships, Design ) 20 | 2. What does a software architect do? 21 | 3. Where do architectures come from? (NFRs, ASRs, Quality Requirements; Stakeholders, Organisations, Technical Environments… ) 22 | 4. Architecture Views (Logical view, Process view, Physical view, Development view + Use case scenarios…) 23 | 5. Architectural activities and process 24 | 6. Software architecture knowledge areas 25 | 26 | #### 2. Quality Attributes 27 | 28 | 1. Software Requirements (Functional requirements, Quality requirements (NFRs), Constraints ) 29 | 2. Modeling quality attribute scenarios: (Source, Stimulus, Artefact, Environment, Response, Measure) 30 | 3. Availability, Interoperability, Modifiability, Performance, Security, Testability, Usability, X-ability 31 | 4. Tactics for quality attributes 32 | 5. Architecturally Significant Requirements (How to gather and identify ASRs: Requirements, Interviews, Business goals, Utility tree) 33 | 34 | #### 3. Architecture Patterns 35 | 36 | 1. Architecture Patterns (Context, Problem, Solution: elements + relations + constraints ) 37 | 2. Module Patterns (Layered pattern ) 38 | 3. Component-Connector Patterns (Broker pattern, Model-view-controller pattern, Pipe-and-filter pattern, Client-server pattern, Peer-to-peer pattern, Service-oriented pattern, Publish-subscribe pattern, Share-data pattern) 39 | 4. Allocation Patterns (Map-reduce pattern, Multi-tier pattern ) 40 | 5. Patterns vs. Tactics 41 | 42 | #### 4. Designing Architecture 43 | 44 | 1. General Design Strategy (Abstraction, Decomposition, Divide & conquer, Generation and test, Iteration, Reuse ) 45 | 2. Attribute-Driven Design (ADD) 46 | 3. Choose a part to design 47 | Marshal all ASRs for that part 48 | Create and test a design for that part 49 | Inputs to and outputs of ADD 50 | 8-step process: 1. confirm requirements, 2. choose an element to decompose, 3. identify ASRs, 4. 51 | choose a design satisfying ASRs, 5. instantiate elements & allocate responsibilities, 6. define 52 | interface, 7. verify & refine requirements, 8. repeat step 2-7 until all ASRs satisfied 53 | 54 | #### 5. Documenting Architecture 55 | 56 | 1. Views and Beyond : Styles (viewpoints), patterns and views 57 | Structural views: module views, component-and-connector views, allocation views 58 | Quality views 59 | 2. Documenting views: 1. build stakeholder/view table, 2. combine views, 3. prioritise & stage 60 | 3. Beyond views: documentation info & architecture info (mapping between views) 61 | 4. Documentation package: views + beyond 62 | 63 | #### 6. Evaluating Architecture 64 | 65 | 1. Stakeholders involved in ATAM 66 | 2. Inputs to and outputs of ATAM 67 | 3. Phase 0: Partnership & preparation 68 | 4. Phase 1: Evaluation - 1 present ATAM, 2. present business drivers, 3. present architecture, 4. identify architectural approaches, 5. generate utility tree, 6. analyse architectural approaches 69 | 5. Phase 2: Evaluation - 2 1. present ATAM & results, 7. brainstorm & prioritize, 8. analyse architectural approaches, 9. present results 70 | 6. Phase 3: Follow-up 71 | 72 | #### 7. Software Product Lines 73 | 74 | 1. Software Product Lines (Engineering). 75 | 76 | Product = core assets + custom assets 77 | Reusability and Modifiability 78 | 79 | 2. Product Line Architecture 80 | 81 | Reuse: find, understand, and use (invoke) 82 | Variation: forms of variation * software entity varied * binding time 83 | Architecture: variation points 84 | 85 | 3. SPL Practice Areas and Patterns 86 | 87 | 29 practice areas and 22 patterns 88 | 89 | 90 | 91 | ## 最终考试 92 | 93 | 简答题、论述题、设计分析题 94 | 95 | 英⽂题⽬、中⽂或英⽂答题 96 | 97 | 个别题⽬可能需画图 98 | 99 | 基础内容70% 100 | 101 | ⾼阶内容30% 102 | 103 | 104 | 105 | 个人认为设计分析题就是其中的高阶内容。 106 | 107 | 画图可能还要再准备一下。 108 | 109 | 110 | 111 | ## 往年考题 112 | 113 | ### 15年考题 114 | 115 | 1. Where do software architecture come from? List five possible sources of software architecture. 116 | 2. **What distinguishes an architecture for a software product line from an architecture for a simple product?** 117 | 3. **How to model quality attribute scenarios? Graphically model two quality attributes in "stimulus-response" format: availability and performance.** 118 | 4. Describe relationships between architecture patterns and tactics. List four tactics names and describe their usage. 119 | 5. **Briefly describe the general activities involved in a software architecture process.** 120 | 6. **Mapping, and list 4 views for each style. (sa07, p.9)** 121 | 7. Explain the context, benefits and limitations of Broker Architecture Pattern. 122 | 8. Why should a software architecture be documented using different views? Give the name and purposes of 4 example views. 123 | 9. Briefly describe the fundamental principles of SOA and discuss the impact of SOA on quality attributes like interoperability, scalability and security. 124 | 10. **Describe outputs generated from each phase of ATAM process.** 125 | 11. Why SPL and MDA have high reusability? Compare and discuss their commonality and differences. 126 | 127 | 128 | 129 | ### 17年考题 130 | 131 | 1. **Briefly describe the general activities in a software architecture process, and the major inputs and outputs at each activity.** 132 | 2. **What distinguishes an architecture for a software product line from an architecture for a single product?** 133 | 3. What are generic design strategies applied in designing software? Give a concise working example with software architecture for each strategy. 134 | 4. **How to model quality attribute scenarios? Graphically model two quality attributes in “stimulus-response” format: availability and modifiability.** 135 | 5. **Describe outputs generated from each phase of ATAM process.** 136 | 6. **Map, and list four views of each category of style.** 137 | 7. What are ASR? List four sources and methods for extracting and identifying ASRs. 138 | 8. Please name at least three Object-Oriented principles, and explain how they are applied in Strategy pattern? 139 | 9. What should be included in a typical software architecture documentation package? Briefly describe each component and its purpose. 140 | 10. Describe 4+1 view 141 | 11. 软件设计的的三个变化维度,每个维度的变化点。differing binding time如何影响可修改性和可测试性。 142 | 143 | 144 | 145 | Variation: forms of variation * software entity varied * binding time 146 | 147 | 148 | 149 | ### 18 年考题(梁神回忆) 150 | 151 | 1. 软件架构的关注点有哪些?利益相关方有哪些? 152 | 2. Software requirements, quality attributes, ASRs 的区别和联系 153 | 3. What is the nature of component-connector style? 以 MVC pattern 举例 154 | 4. 如何对质量属性场景建模?画出 availability 和 modifiability 的刺激-响应图 155 | 5. risks, sensitivity points, trade-off points 是什么?各举一个例子 156 | 6. **连线,并对每种 style 列出四种视图** 157 | 7. Layered pattern 和 Multi-tier pattern 的区别 158 | 8. 描述 ADD 过程 159 | 9. **为什么软件架构需要用不同的视图描述?举出四种视图的例子(列出名称和目的)** 160 | 10. 软件产品线架构如何实现可变性?描述可变性机制的工作方式 161 | 11. 设计一个飞行模拟软件,要求能模拟多种飞机的特性。为了在将来支持更多飞机种类,要求使用策略模式。画出架构图和类图 162 | 12. 太复杂,忘了 163 | 164 | 165 | 166 | ### 19年押题 167 | 168 | 这 7 个估计考的概率很大, 看明天是不是打脸吧….. 169 | 170 | 1. ATAM (看规律ATAM 和 ADD 轮流考) 171 | 2. 连线,并对每种 style 列出四种视图(每年都考,这个必然了) 172 | 3. 各种不同视图 (列举)(4+1 或者后面的) 173 | 4. 如何对质量属性场景建模?画出 availability 和 *** 的刺激-响应图 (可用性是一定要考的,其他的不好说。 概率: 性能 > 可修改性 > 其他) 174 | 5. 软件产品线…..(肯定会考,但是没法猜考什么) 175 | 6. 几种设计模式(很可能考设计题,要画图) 176 | 7. 微服务架构 177 | 178 | 179 | 180 | ### 19 年最终考题 (个人回忆) 181 | 182 | 1. 如何对质量属性场景建模?画出 Interoperability 和 modifiability 的刺激-响应图 183 | 2. What are ASR? List four sources and methods for extracting and identifying ASRs. 184 | 3. 4+1 视图介绍(还要画图,我的图画的的有点问题,去wiki百科上可以看) 185 | 4. What are generic design strategies applied in designing software? Give a concise working example with software architecture for each strategy. (和17年一样的) 186 | 5. Map, and list four views of each category of style.(每年必考题) 187 | 6. What should be included in a typical software architecture documentation package? Briefly describe each component and its purpose. (和17年基本一样) 188 | 7. 描述 在 ATAM 的每一个过程中 有哪些 stake holder 和他们的职责 189 | 8. 软件产品线架构如何实现可变性?描述可变性机制的工作方式,和变化点。 (和去年一样) 190 | 9. Explain the context, benefits and limitations of Broker Architecture Pattern. 191 | 10. 微服务 和 SOA 的区别,相同点 192 | 11. 一个买票系统的设计题,不同的角色有不同的打折方案,用策略模式设计, 最后画图,还要说明策略模式的使用场景。 193 | 12. 设计题,和 15 年的设计题一模一样 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /machine-learning/N2N.md: -------------------------------------------------------------------------------- 1 | ## N2N 学习论文解析 2 | 3 | ### 标题 4 | 5 | N2N LEARNING: NETWORK TO NETWORK COMPRESSION VIA POLICY GRADIENT REINFORCEMENT LEARNING 6 | 7 | 使用策略梯度的方法进行从网络到网络的模型压缩。 8 | 9 | ### 摘要 10 | 11 | 当前的深层神经仍然被硬件和速度深深的限制着。 传统的模型尝试去用启发式的方法压缩修改压缩框架。因为所有的架构搜索空间非常巨大,修改深层神经网络的架构十分困难。 所以在这篇文章中我们使用强化学习的方式来解决这个问题。 我们的方法接受一个比较大的老师网络作为输入并且输出一个压缩之后的学生网络。 在我们的方法第一步,使用循环神经网络来不断的从大的 老师网络中移除层,在第二部中,另一个循环神经网络对每一层进行压缩大小。 最终的结果网络使用一个 reward 来进行评估,这个 reward 根据准确率和压缩率的得出。 我们的方法利用这个 reward 值去找到一个最优的学生网络。 12 | 13 | 14 | 15 | ### 方法 16 | 17 | #### 1. 马尔可夫决定过程 18 | 19 | 我们把找到一个压缩之后的架构看做成一个一系列的决策过程。 这个过程就是马尔可夫决策过程。 正式的讲,马尔可夫决策过程被定义成 三元组{S, A, T, r, y} 20 | 21 | ##### 状态 22 | 23 | S 是状态空间,是一个有限的包含了全部可能从老师网络中推导出的网络架构集合。 比如说 VGG 网络代表了初始状态 s, 通过在第一层去除掉一个卷积核,我们得到了一个新的网络架构 s'. 24 | 25 | ##### 动作 26 | 27 | A 是一个有限的动作集合 可以把 一个网络架构变成另一个网络架构。 在我们方法中,有两种动作类型: 去除一层 和 去除一层中的参数。后面会单独描述这两种动作类型。 28 | 29 | ##### 转换函数 30 | 31 | S * A -> S 是动态的状态转换,这个转换被称作是 T,这个函数实际上是确定性的。 32 | 33 | ##### 折扣因子 34 | 35 | Y 是折扣因子,我们把 y 设置成1,所以这样所有的 reward 的值和实际返回的值(起效果的值)是相等的。 36 | 37 | ##### 奖赏 38 | 39 | r: S->R 是一个 奖赏函数。 这个网络架构的奖赏可以被翻译成一个和给定网络架构 s 相关联的分数。 注意我们对于临时状态定义了 0 作为 reward,代表了不完成状态。 后面也会单独讲奖励函数。 40 | 41 | 42 | 43 | #### 2. 学生-老师 强化学习 44 | 45 | 在 MDP设定下, 强化学习的任务已经变成了学习一个优化的策略 π:S->A, 这个策略可以在整个网络下取得一个最大值。 46 | 47 | 全部的 reward 最终会被定义为每一个 reward 求和。 48 | 49 | 我们采用一个 策略梯度强化学习方法并且迭代的更新策略根据对于 reward 的采样估计。 对于动作空间的设计对于 策略梯度方法 去有效的搜索状态空间是十分重要的。 如果这个动作以一种十分增量式的方法被选择,对于神经网络做出很大的改变会需要一个很长的序列。 为了解决这个问题,我们提出了一个两步的强化学习过程。 在第一步我们的策略去决定是否要保留一个特定的层。 在第二步,一个不同的策略选择一些剩下的层该保留哪些变量的决策。 这样我们就能够有效的去探索我们的状态空间了。 50 | 51 | 还有一个详细的算法图来介绍这个算法的具体。 52 | 53 | ##### 去除层 54 | 55 | 在去除层的阶段,动作 At 用来决定是保留还是去除一层。 这个操作的动作轨迹长度是L,L是神经网络的总层数。 在去除层的每一步t,双向 LSTM 策略观察到了隐层状态, ht-1 和 ht+1 还有 xt 关于当前的层。最终的决策函数是 π(at|ht-1,ht+1,xt)关于当前的层 l 的信息是 56 | 57 | Xt = (l,k,s,p,n,S(start),S(end)) 58 | 59 | l 是当前层的类型, k 是核大小, s 是步长, p 是padding,n 是输出的数量。 可以看出这仅仅是对于卷积层的操作? 60 | 61 | ##### 压缩层 62 | 63 | 对于一层的收缩策略轨迹的长度是这一层中的可配置变量的数量。 在收缩收缩阶段的每一个步骤 t, 这个策略观察到了隐含的状态 ht-1, 这个之前采样好的动作 at-1 和当前的层信息 xt, 这样构成了一个相类似的策略。 64 | 65 | ##### 奖赏函数 66 | 67 | 奖赏函数的设计对于学习策略是至关重要的。 一个设计的不好的奖赏函数不能够有效的区分好的网络架构和不好的网络架构。 68 | 69 | 模型压缩的目标是去最大化压缩同时还能保持一个很高的准确率。 我们的奖赏函数对于高压缩率,低准确率模型的惩罚要大于高准确率,低压缩率的模型。 70 | $$ 71 | R = R_c \times R_a 72 | = C(2-C)\times \frac {A}{A_t} 73 | $$ 74 | C 是学生模型的相对压缩率, A是学生模型的验证准确率,At 是老师模型的验证准确率,作为一个常数被提供。 Rc 和 Ra 分别对应于压缩和准确率的奖赏函数。 75 | 76 | ##### 奖赏函数的约束 77 | 78 | 可以把一些硬件和资源约束加入到 奖赏函数的定义中,然后 reward 就会变成一个分段函数, 79 | 80 | 81 | 82 | ##### 优化 83 | 84 | 我们现在对我们的每一个随机策略来描述优化过程。因为两个的优化过程是完全一样的,所以我们统一使用π来进行代表。 对于每一个策略网络会有自己不同的 θ参数。 85 | 86 | 我们的目标函数是 对于一系列行动的 reward 的期望值。 87 | $$ 88 | \bigtriangledown_{\theta}J(\theta) = \bigtriangledown_{\theta}E_{a_{1:t}-p_\theta(R)} 89 | $$ 90 | 上面其实就是一些列的 policy-gredient 的公式,还要再复习一下 policy-gredient 91 | 92 | 93 | 94 | ##### 知识蒸馏 95 | 96 | 学生网络在训练过程中用到的数据是由老师网络标注的,而不是去使用硬标记,我们使用非正则化的对数概率值。 97 | 98 | 这个蒸馏的本质其实就是在学生的损失函数中加入关于针对老师网络的单独的项。 -------------------------------------------------------------------------------- /machine-learning/network-compression.md: -------------------------------------------------------------------------------- 1 | ## 网络压缩 2 | 3 | 4 | 5 | ### 1. 概述 6 | 7 | 深度神经网络(DNN)已经被广泛的应用在了很多领域,但是令人望而却步的计算复杂度使得他们难以在移动设备上部署。 于是就有了神经网络压缩算法,可以把一个大小为 几百 M的模型压缩到不到10M。 然而,为这样的模型选择超参数来取得一个压缩效果很好的网络是十分困难的。 为了让DNN压缩技术更加简单的被应用并且减少对熟练的人类专家的需求。 自动神经网络压缩算法被提出了,在学术界和工业界都有着十分重大的影响力。 8 | 9 | 10 | 11 | ### 2. 分类 12 | 13 | 自动压缩问题在不同的限制下可以被大体上分成三种。 14 | 15 | 第一种是 硬件导向的模型压缩技术,用来去限制精度上的损失。 它不依赖于启发式和基于规则的策略, 这两种策略需要专家去手动的探索很大的搜索空间 并且对于模型的大小, 速度 和 准确率做出一些权衡。 16 | 17 | **第二种是有 训练数据和老师网络的情况下的资源受限的自动模型压缩。 给出受限制的计算资源,核心的思想是去输入一个大型的老师网络 最终 输出一个相对比较小的 学生网络。** 18 | 19 | 第三种是 在有训练数据的情况下神经网络架构搜索。 这个问题在这三个压缩问题里面是最苦难的,因为我们必须去设计一个新颖的神经网络架构并且满足硬件资源的约束。 20 | 21 | 22 | 23 | 上面的三个任务中我目前负责第二个。 24 | 25 | ### 3. 目标 26 | 27 | 我们提出了一个算法来自动的找到最优的压缩策略,把确定的资源限制作为参数去输入。 我们把一个比较大型的学生网络作为输入并且将其压缩作为比较小的学生网络。 同时能够保持分类效果。 我们的算法不仅仅会考虑连续压缩率策略同时也会考虑把网络层移除的策略。 28 | 29 | 30 | 31 | #### 4. 方法 32 | 33 | 随着现代的神经网络变得越来越深和越来越大,他们变得的越来越慢并且需要很高的计算资源,而普通的移动设备和终端设备并不会具备这种计算资源。 34 | 35 | 给出可以在移动设备上使用的受限制的计算资源,设计一个能够平衡资源效率和模型准确率的模型是非常苦难的。 进一步讲,每一种移动设备都有自己的软件和硬件特点,并且会需要不同的网络架构来做到最好的准确率和效率的平衡。 36 | 37 | 受到知识蒸馏这种使用不同的训练技巧去让一个小的网络模仿一个很大的网络并且可以和这个很大的网络能够在运行的时候去的相同的性能。 我们的方法使用一个大型的 老师网络 作为输入并且去输出一个压缩好的从老师网络中提取出来的学生网络。因为对于不同的任务修改网络架构师是十分困难的,所有我们通过引入强化学习的方法来对网络进行自动化的压缩。 38 | 39 | 我们的目标是在给定一个资源限制的情况下使用强化学习学习到一个最优的压缩策略,把一个老师网络作为输入,系统自动化的输出一个比较小的学生网络。 我们把这个序列化的去找到学生网络架构的过程作为一个决策的过程,并且分别定义了 状态空间,动作空间 和 reward. 更加具体的讲,这里有两类动作,把一层移除和让一个网络层有着更高的稀疏率。 我们想出了一个连续压缩率控制策略通过一个 DDPG agent. 我们的 reward 函数是基于准确率和预先定义好的硬件资源限制得出的。 40 | 41 | 我们应用一个两步的层移除和层压缩的过程去学习到怎样去自动的压缩一个大型的神经网络。 我们的方法和不仅仅会压缩层的数量同时也会去压缩每一层上的可训练参数。 进一步讲,我们加速了我们的网络层的收缩使用了一个简单的,非RNN的控制器和更快的探索使用连续的动作空间。 42 | 43 | 44 | 45 | #### 5. 相关工作 46 | 47 | 对于第二个任务,已经有了很多基于知识蒸馏的工作。 知识蒸馏是通过一个大的预训练老师模型来取得一个比较小的,高准确率的学生网络的方法。 48 | 49 | 1. Hinton G., Vinyals O., Dean J. (2015). Distilling the knowledge in a neural network. arXiv preprint arXiv:1503.02531. 50 | 2. Ba, J., & Caruana, R. (2014). Do deep nets really need to be deep?. In Advances in neural information processing systems (pp. 2654-2662). 51 | 3. Chen, T., Goodfellow, I., & Shlens, J. (2015). Net2net: Accelerating learning via knowledge transfer. In International Conference on Learning Representations (ICLR’16). 52 | 53 | 上面是三个相关工作,在第一个论文中,作者展示了从一个 teacher 网络 和 给定数据区训练会比只使用数据区训练的效果好的多。 然后现在的知识蒸馏方法需要小心的设计学生网络。 我们训练了一个控制器去学习优化学生架构,而不是用手工设计的方法。 54 | 55 | 并且,之前的针对模型搜索的强化学习方法引入了基于RNN的网络通过 策略控制器的方法,但是这种方法非常消耗时间。 56 | 57 | 1. Ashok, A., Rhinehart, N., Beainy, F., Kitani, K.M.: N2n learning: Network to network compression via policy gradient reinforcement learning arXiv preprint arXiv:1709.06030 (2017) 58 | 2. Cai, H., Chen, T., Zhang, W., Yu, Y., Wang, J.: Reinforcement learning for architecture search by network transformation. arXiv preprint arXiv:1707.04873 (2017) 59 | 60 | 并且对于层的压缩率是离散的并且在限制在一定的范围内。 然而,我们发现模型压缩的准确率对于每一层的稀疏度十分敏感。 所以,我们引入了一个简单的 非 RNN 控制器 并且 定义了 一个连续的动作空间来应对我们每一层的压缩过程。 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /machine-learning/semi-vae.md: -------------------------------------------------------------------------------- 1 | # 使用变分自动编码器进行半监督学习 2 | 3 | 主要介绍如何使用变分自动编码器进行半监督学习。 特别的会介绍在 “Semi-supervised Learning with Deep Generative Models” 这篇论文中用到的技术。 4 | 5 | 6 | 7 | ## 半监督学习 8 | 9 | 半监督学习是一类尝试去使用无监督数据去进行监督学习的技术。 半监督学习在有监督学习和无监督学习之间,因为在其中可以同时使用有监督数据和无监督数据。 10 | 11 | 如果你有大量的无标注的数据。 你大多数情况下不会有一个基准的处理这些数据的准则。 比如说,在互联网上有着上千亿的图片,但是只有其中的一小部分是有着清楚的标注的。 所以我们的目标是使用大量的无标注数据获取最佳性能。 12 | 13 | 人类不知为何对这种工作非常擅长。 比如说大多数人没有肩见过食蚁兽,但是只要我们看过它的非常少的几张照片,就可以对其进行非常准确的分类。 我门对这个任务非常擅长是因为我们的大脑已经学习到了足够的共同特征,可以迅速对新的种类进行学习和分类。 对于机器来说,并没有什么不同,我们想要让机器通过无监督的学习到很多的基础特征来帮助真实的任务(只有少量的数据)。 14 | 15 | 16 | 17 | 18 | 19 | ## 变分自动编码器 20 | 21 | 首先介绍什么是变分自动编码器 22 | 23 | ### 自动编码器 24 | 25 | 自动编码机Auto-Encoder (AE)由两部分encoder和decoder组成,encoder输入x数据,输出潜在变量z,decoder输入z然后输出一个x’,目的是让x’与x的分布尽量一致,当两者完全一样时,中间的潜在变量z可以看作是x的一种压缩状态,包含了x的全部feature特征,此时监督信号就是原数据x本身。 26 | 27 | ### 变分自动编码器 28 | 29 | 变分自动编码机VAE是自动编码机的一种扩展,它假设输出的潜在变量z服从一种先验分布,如高斯分布。这样,在训练完模型后,我们可以通过采样这种先验分布得到z’,这个z’可能是训练过程中没有出现过的,但是我们依然能在解码器中通过这个z’获得x’,从而得到一些符合原数据x分布的新样本,具有“生成“新样本的能力。 30 | 31 | VAE是一种生成模型,它的目标是要得到 p(z|x) 分布,即给定输入数据 x 的分布,得到潜在变量 z 的分布, 与其他的生成模型一样,它计算的是x和z的联合概率分布p(x,z)(如朴素贝叶斯模型通过计算p(x,z)/p(x) 得到p(z∣x) ,当然它不是直接计算这个联合概率分布,而是借助一些公式变换求解。 32 | 33 | 34 | 35 | 前面讲过,变分自动编码机的目的是想知道观测数据x背后的潜在变量z分布,即p(z∣x) ,举个简单的例子,比如天气是我们的观测数据x,但我们想知道影响天气变化背后的一些无法观测的因素z,这个z就像自然法则一样能够左右最后观测到的天气,这样我们以后描述某个天气,就可以完全量化为对应的潜在变量z。对于这个例子,VAE/AE都能完成这个事情,但如果现在我们想生成一些新的天气样本来作为研究,这个时候只有VAE可以很容易做这个事情:拟合现有样本分布的一个潜在变量的先验分布,通过采样这个先验分布来获得新的样本;而对于AE这个事情就比较难了:由于每个样本x被固定编码为对应的z,我们无法知道潜在样本的分布(若此时我们知道了z的分布,就等于知道了真实数据x的分布,这显然是不可能的,相比VAE的解决方案是把真实数据x对应的潜在分布映射到一个先验分布上),若AE硬要获得新样本怎么做呢,此时只能随机采样z了,很显然我们无法验证:根据这个z是否能正确地还原出一个符合真实样本x的新样本。 36 | 37 | 除了单纯“生成“新的样本用途,生成模型还可以用来去噪声,比如现在的图片里有雾霾,我们想把图片里的雾霾去掉,还原没有雾霾的样子,就可以用VAE/AE做:把有雾霾的图片当作输入x,对应的无雾霾的图片(假设我们能够在天气好的时候获得)作为最后要还原的x’训练VAE模型,如果训练的足够好的话,以后再任意拿一张有雾霾的图片,VAE能够还原出这个图片没有雾霾的样子,这就是生成模型的优势。当然,判别模型也能做这个事情:在给定原图像的情况下,尽量拟合原图像的变换图像,但是若测试时出现了之前训练过程中没有出现的图像,效果会不好,因为判别模型是基于条件概率p(x′∣x) 若新的条件x模型都没见过,效果肯定不好啊,所以判别模型更注重泛化能力。而生成模型会去拟合x和x’联合概率分布p(x,x′) ,因此p(x′∣x)的计算只需要除以边缘概率分布p(x) p(x)p(x)即可,而对于VAE来说,它拟合的其实是x和潜在变量z的联合概率分布p(x,z),获得p(z∣x) 从而间接生成x’。 38 | 39 | 40 | 41 | VAEs 是一类重要的生成模型, 除了 VAEs 还有一类十分重要的模型 GANS。 42 | 43 | 44 | 45 | ### VAE 数学推导 46 | 47 | #### KL 散度 48 | 49 | **相对熵**(relative entropy)又称为**KL散度**(**Kullback–Leibler divergence**,简称**KLD**),信息散度(information divergence),信息增益(information gain)。 50 | 51 | **KL散度**是两个概率分布P和Q差别的非对称性的度量。 KL散度是用来 度量使用基于Q的编码来编码来自P的样本平均所需的额外的位元数。 典型情况下,P表示数据的真实分布,Q表示数据的理论分布,模型分布,或P的近似分布。 52 | 53 | 离散型随机变量,P和Q的概率分布 KL 散度 54 | $$ 55 | D_{kl}(P||Q)=-\sum_{i}P(x)ln\frac{Q(i)}{P(i)} 56 | $$ 57 | 58 | 59 | 60 | 连续随机变量,可以按照积分的方式进行定义 61 | 62 | $$ 63 | D_{kl}(P||Q)=-\int_{-\infty}^{\infty}P(x)ln\frac{Q(i)}{P(i)}dx 64 | $$ 65 | 66 | 67 | ![](http://latex.codecogs.com/gif.latex?\\) 68 | 69 | 70 | KL 的 散度的值是非负值,当且仅当 P = Q 时,KL 散度的值是0。 71 | 72 | KL 并不是一个度量, 从 P 到 Q的距离通常不等于从Q到P的距离。 73 | 74 | 75 | 76 | #### VAE 下界推导 77 | 78 | 为了求解真实的后验p(z∣x) p(z|x)p(z∣x)概率分布,VAE引入一个识别模型q(z∣x) q(z|x)q(z∣x)去近似p(z∣x) p(z|x)p(z∣x),那么衡量这两个分布之间的差异自然就是相对墒了,也就是KL散度,VAE的目的就是要让这个相对墒越小,因此推导从相对墒开始: 79 | 80 | $$ 81 | D_{kl}q(z|x)||p(z|x)=-\int P(x)log\frac{q(z|x)}{p(z|x)}dz=E_{z\sim q(z|x)}log\frac{q(z|x)}{p(z,x)} + logP(x) 82 | $$ 83 | 84 | 85 | 86 | 令上述期望项为 L(x), 可以明显的看出 L(x) <= logP(x) 因为 KL 散度的值是永远大于0的。 87 | 88 | 所以目标可以变为优化 L(x) 89 | 90 | L(x) 经过贝叶斯展开和蒙特卡洛采样后,可以变成如下的形式 91 | $$ 92 | L(x)=-KLq(z|x)||p(z|x)+E_{z\sim q(z|x)}logP(z,x) 93 | $$ 94 | 95 | $$ 96 | =\frac{1}{2}\sum_{j=1}^{J}1+log(\sigma_j^2)-\mu_j^2-\sigma_j^2+\frac{1}{L}\sum_{l=1}{L}logp(x|z_l) 97 | $$ 98 | 99 | 100 | 其中 sigma 和 mu 是均值和方差, 后面的 zl 是蒙特卡罗采样的结果。 只要把这个作为一个损失函数进行处理即可。 101 | 102 | #### python 代码实现 103 | 104 | ##### 1. 编码器 105 | 106 | 编码器的输出分两部分,一部分表示mean,一部分表示标准差std,其中由于标准差是恒大于0,因此用了softplus激活函数: 107 | 108 | ```python 109 | def gaussian_MLP_encoder(...): 110 | # 1st hidden layer 111 | ... 112 | 113 | # 2nd hidden layer 114 | ... 115 | 116 | # output layer 117 | wo = tf.get_variable('wo', [h1.get_shape()[1], n_output * 2], initializer=w_init) 118 | bo = tf.get_variable('bo', [n_output * 2], initializer=b_init) 119 | gaussian_params = tf.matmul(h1, wo) + bo 120 | 121 | # The mean parameter is unconstrained 122 | mean = gaussian_params[:, :n_output] 123 | # The standard deviation must be positive. Parametrize with a softplus and 124 | # add a small epsilon for numerical stability 125 | stddev = 1e-6 + tf.nn.softplus(gaussian_params[:, n_output:]) 126 | ``` 127 | 128 | ##### 2. 解码器 129 | 130 | 输出的大小与输入一致,其中每个元素代表着此位置的像素值为0的概率(或者255,根据输入来定),所以用sigmoid激活函数 131 | 132 | ```python 133 | def bernoulli_MLP_decoder(...): 134 | # 1st hidden layer 135 | ... 136 | 137 | # 2nd hidden layer 138 | w1 = tf.get_variable('w1', [h0.get_shape()[1], n_hidden], initializer=w_init) 139 | b1 = tf.get_variable('b1', [n_hidden], initializer=b_init) 140 | h1 = tf.matmul(h0, w1) + b1 141 | h1 = tf.nn.elu(h1) 142 | h1 = tf.nn.dropout(h1, keep_prob) 143 | 144 | # output layer-mean 145 | wo = tf.get_variable('wo', [h1.get_shape()[1], n_output], initializer=w_init) 146 | bo = tf.get_variable('bo', [n_output], initializer=b_init) 147 | y = tf.sigmoid(tf.matmul(h1, wo) + bo) 148 | ``` 149 | 150 | #### 3. 损失函数 151 | 152 | ```python 153 | # 编码器得到标准差和均值向量 154 | mu, sigma = gaussian_MLP_encoder(x_hat, n_hidden, dim_z, keep_prob) 155 | 156 | # reparameterization 重参数采样得到z 157 | z = mu + sigma * tf.random_normal(tf.shape(mu), 0, 1, dtype=tf.float32) 158 | 159 | # 解码器传入z,输出y 160 | y = bernoulli_MLP_decoder(z, n_hidden, dim_img, keep_prob) 161 | y = tf.clip_by_value(y, 1e-8, 1 - 1e-8) 162 | 163 | # marginal_likelihood loss为y与输入数据x之间交叉墒,即解码器的损失 164 | marginal_likelihood = tf.reduce_sum(x * tf.log(y) + (1 - x) * tf.log(1 - y), 1) 165 | marginal_likelihood = tf.reduce_mean(marginal_likelihood) 166 | 167 | # KL_divergence为z与标准高斯分布之间的差距,即编码器的损失 168 | KL_divergence = 0.5 * tf.reduce_sum(tf.square(mu) + tf.square(sigma) - tf.log(1e-8 + tf.square(sigma)) - 1, 1) 169 | KL_divergence = tf.reduce_mean(KL_divergence) 170 | 171 | # 变分下界L(x),目标最大化 172 | ELBO = marginal_likelihood - KL_divergence 173 | 174 | # 令损失函数为-L(x),目标梯度下降最小化 175 | loss = -ELBO 176 | ``` 177 | 178 | 179 | 180 | ## VAE 进行半监督学习 181 | 182 | 由于上述VAE的特性,因为VAE可以自己产生新的数据 183 | 184 | 所以使用VAE进行半监督学习的方法的思路可以简单的理解为: 先训练一个VAE, 然后利用VAE对所有的未标注数据产生标注数据。 产生了全部标注标注数据后进行正常的监督学习的训练过程。 185 | 186 | 1. Train a VAE using *all* our data points (labelled and unlabelled), and transform our observed data (XX) into the latent space defined by the ZZ variables. 187 | 2. Solve a standard supervised learning problem on the *labelled* data using (Z,Y)(Z,Y) pairs (where YY is our label). 188 | -------------------------------------------------------------------------------- /resource/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/exlaw/Notes/c59c1eb89c7ddb40d5109b27f0ae9b2bd638e9ed/resource/img.jpg --------------------------------------------------------------------------------