Terminology

  • Rest: Representational State Transfer
  • API: Application Programming Interface

RESTful API Main Criteria:

  • Client-server

    A client-server architecture made up of clients, servers, and resources, with requests managed through HTTP.

  • Stateless

    Stateless client-server communication, meaning no client information is stored between get requests and each request is separate and unconnected.

  • Cache

    Cacheable data that streamlines client-server interactions.

  • Uniform Interface

    A uniform interface between components so that information is transferred in a standard form.

    This requires that:

    • resources requested are identifiable and separate from the representations sent to the client.
    • resources can be manipulated by the client via the representation they receive because the representation contains enough information to do so.
    • self-descriptive messages returned to the client have enough information to describe how the client should process it.
    • hypertext/hypermedia is available, meaning that after accessing a resource the client should be able to use hyperlinks to find all other currently available actions they can take.
  • Layered System

    A layered system that organizes each type of server (those responsible for security, load-balancing, etc.) involved the retrieval of requested information into hierarchies, invisible to the client.

  • Code-on-demand (optional)

    The ability to send executable code from the server to the client when requested, extending client functionality.

Ref

  1. npm install fail with unknown reason.

    Try clean the cache before installation:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # Clean cache
    rm -rf node_modules
    rm package-lock.json
    npm cache clean -f

    # Install packages
    npm i

    # Check npm packages version
    npm outdated

    # Update pacakges
    npm update

The UML Class diagram is a graphical notation used to construct and visualize object oriented systems. A class diagram in the Unified Modeling Language (UML) is a type of static structure diagram that describes the structure of a system by showing the system’s:

  • classes
  • their attributes
  • operations (or methods)
  • and the relationships among objects.

UML Class Notation

A class represent a concept which encapsulates state (attributes) and behavior (operations). Each attribute has a type. Each operation has a signature. The class name is the only mandatory information.

02-class-notation.png

Class Visibility

The +, - and # symbols before an attribute and operation name in a class denote the visibility of the attribute and operation.

04-class-attributes-with-different-visibility.png

  • + denotes public attributes or operations
  • - denotes private attributes or operations
  • # denotes protected attributes or operations

Parameter Directionality

Each parameter in an operation (method) may be denoted as in, out or inout which specifies its direction with respect to the caller. This directionality is shown before the parameter name.

05-parameter-directionality.png

Perspectives of Class Diagram

The choice of perspective depends on how far along you are in the development process. During the formulation of a domain model, for example, you would seldom move past the conceptual perspective. Analysis models will typically feature a mix of conceptual and specification perspectives. Design model development will typically start with heavy emphasis on the specification perspective, and evolve into the implementation perspective.

A diagram can be interpreted from various perspectives:

  • Conceptual: represents the concepts in the domain
  • Specification: focus is on the interfaces of Abstract Data Type (ADTs) in the software
  • Implementation: describes how classes will implement their interfaces

The perspective affects the amount of detail to be supplied and the kinds of relationships worth presenting. As we mentioned above, the class name is the only mandatory information.

06-perspective-of-class-diagram.png

Relationships between classes

类的关系有泛化(Generalization)、实现(Realization)、依赖(Dependency)和关联(Association)。其中关联又分为一般关联关系和聚合关系(Aggregation), 合成关系(Composition)。

07-relationships-between-classes.png

虚线箭头指向依赖;
实线箭头指向关联;
虚线三角指向接口;
实线三角指向父类;
空心菱形能分离而独立存在,是聚合;
实心菱形精密关联不可分,是组合;

  1. 泛化(generalization) :表示 is-a 的关系,是对象之间耦合度最大的一种关系,子类继承父类的所有细节。直接使用语言中的继承表达。在类图中使用带三角箭头的实线表示,箭头从子类指向父类。

    inheritance

    • An abstract class name is shown in italics.
  2. 实现(Realization):在类图中就是接口和实现的关系。在类图中使用带三角箭头的虚线表示,箭头从实现类指向接口。

    realization

  3. 依赖(Dependency) :对象之间最弱的一种关联方式,是临时性的关联。代码中一般指由局部变量、函数参数、返回值建立的对于其他对象的调用关系。一个类调用被依赖类中的某些方法而得以完成这个类的一些职责。在类图使用带箭头的虚线表示,箭头从使用类指向被依赖的类。

    15-dependency-example.png
    dependency

  4. 关联(Association): 对象之间一种引用关系,比如客户类与订单类之间的关系。这种关系通常使用类的属性表达。关联又分为一般关联、聚合关联与组合关联。

    1. 一般关联。在类图使用带箭头的实线表示,箭头从使用类指向被关联的类。可以是单向和双向。

      association
      association02

    2. 聚合(Aggregation) :表示 has-a 的关系,是一种不稳定的包含关系。较强于一般关联,有整体与局部的关系,并且没有了整体,局部也可单独存在。如公司和员工的关系,公司包含员工,但如果公司倒闭,员工依然可以换公司。在类图使用空心的菱形表示,菱形从局部指向整体。

      aggregation

    3. 组合(Composition) :表示 contains-a 的关系,是一种强烈的包含关系。组合类负责被组合类的生命周期。是一种更强的聚合关系。部分不能脱离整体存在。如公司和部门的关系,没有了公司,部门也不能存在了;调查问卷中问题和选项的关系;订单和订单选项的关系。在类图使用实心的菱形表示,菱形从局部指向整体。
      composition

    Cardinality is expressed in terms of:
    * one to one
    * one to many
    * many to many

    11-associations-with-different-multiplicies.png

    多重性(Multiplicity) : 通常在关联、聚合、组合中使用。就是代表有多少个关联对象存在。使用数字..星号(数字)表示。如下图,一个割接通知可以关联0个到N个故障单。
    multiplicity

Relationship Discrimination

聚合和组合的区别

聚合关系是“has-a”关系,组合关系是“contains-a”关系;聚合关系表示整体与部分的关系比较弱,而组合比较强;聚合关系中代表部分事物的对象与代表聚合事物的对象的生存期无关,一旦删除了聚合对象不一定就删除了代表部分事物的对象。组合中一旦删除了组合对象,同时也就删除了代表部分事物的对象。

依赖和关联的区别

  • 依赖(Dependency)

    从字面理解的话,是说一个类用到了另一个类。这种使用关系是具有偶然性的、临时性的、非常弱的。比如下图中的依赖关系,司机开车,要依赖车。在代码上表现的话一般为函数参数,或者局部变量或者对静态方法的调用。注意依赖关系只能是单向的,并且依赖关系强调的是 使用上的关系

  • 关联(Association)

    • 关联关系强调的是一种结构上的关系
    • 他可以是单向的或者双向
    • 从语义级别(上下文)可以分为聚合和组合,在代码实现上关联和聚合是很像的,主要区别在语义上
    • 一般来说双方关系是平等的,比如我和我的朋友
    • 在java语言上一般表现为全局变量。如person类和company类,顾客和地址,客户和订单

Example

sum

Software to Draw UML Class Diagram

  • Visio
  • Enterprise Architect
  • Rose

Ref

NPM Dependency Management Model

Dependency Resolution

npm3 resolves dependencies differently than npm2.

While npm2 installs all dependencies in a nested way, npm3 tries to mitigate the deep trees and redundancy that such nesting causes. npm3 attempts this by installing some secondary dependencies (dependencies of dependencies) in a flat way, in the same directory as the primary dependency that requires it.

Imagine we have a module, A. A requires B.
a require b

Now, let’s create an application that requires module A.

npm3deps2

Now, let’s say we want to require another module, C. C requires B, but at another version than A.

npm3deps3

However, since B v1.0 is already a top-level dep, we cannot install B v2.0 as a top level dependency. npm v3 handles this by defaulting to npm v2 behavior and nesting the new, different, module B version dependency under the module that requires it – in this case, module C.

npm3deps4

tree
Noted that you can list the dependencies and still see their relationships using npm ls.

If you want to just see your primary dependencies, you can use:

1
npm ls --depth=0

npmlsdepth0

Duplication and Deduping

See Duplication and Deduping article for better illustration.

Use npm dedupe to get rid of duplication.

1
npm dedupe
  • Before dedupe

    npm3deps12

  • After dedupe

    npm3deps13

Comparision with Other Package Management Models

At a high level, npm is not too dissimilar from other package managers for programming languages: packages depend on other packages, and they express those dependencies with version ranges. npm happens to use the semver versioning scheme to express those ranges, but the way it performs version resolution is mostly immaterial; what matters is that packages can depend on ranges rather than specific versions of packages.

Npm installs a tree of dependencies. That is, every package installed gets its own set of dependencies rather than forcing every package to share the same canonical set of packages.

For example, consider two packages, foo and bar. Each of them have their own set of dependencies, which can be represented as a tree:

1
2
3
4
5
6
7
foo
├── hello ^0.1.2
└── world ^1.0.7

bar
├── hello ^0.2.8
└── goodbye ^3.4.0

Most package managers (including RubyGems/Bundler, pip, and Cabal) would simply barf here, reporting a version conflict. This is because, in most package management models, only one version of any particular package can be installed at a time.

In contrast, npm has a somewhat easier job: it’s totally okay with installing different versions of the same package because each package gets its own set of dependencies. In the aforementioned example, the resulting directory structure would look something like this:

1
2
3
4
5
6
7
8
9
node_modules/
├── foo/
│ └── node_modules/
│ ├── hello/
│ └── world/
└── bar/
└── node_modules/
├── hello/
└── goodbye/

Pros

  1. Extremely simple model but get pretty messy quickly.

    Notably,the directory structure very closely mirrors the actual dependency tree. The above diagram is something of a simplification: in practice, each transitive dependency would have its own node_modules directory and so on, but the directory structure can get pretty messy pretty quickly.

  2. Avoid “Dependency Hell”.

    The npm model of package management is more complicated than that of other languages, but it provides a real advantage: implementation details are kept as implementation details. In other systems, it’s quite possible to find yourself in “dependency hell”, when you personally know that the version conflict reported by your package manager is not a real problem, but because the package system must pick a single canonical version, there’s no way to make progress without adjusting code in your dependencies. This is extremely frustrating.

Cons

  1. Larger code size. Worse performance.

    Given the potential for many, many copies of the same package, all with different versions. An increase in code size can often mean more than just a larger program—it can have a significant impact on performance. Larger programs just don’t fit into CPU caches as easily, and merely having to page a program in and out can significantly slow things down. That’s mostly just a tradeoff, though, since you’re sacrificing performance, not program correctness.

  2. Dependency isolation can affect cross-package communication.

    See this Dependency isolation and values that pass package boundaries section for detailed illustration.

    An failure example: Dialog will break if two version of botbuilder-dialog package exists

PeerDependency

PeerDependency: Rather than getting its own copy of a peer dependency, a package expects that dependency to be provided by its dependent.

The peerDependencies requires npm v7. For npm >= 3 and npm <= 6, peerDependencies can be declared but will not be automatically checked and installed.
That is to say, to leverage the peerDependencies feature, we will need to migrate to npm v7 as well as requiring user to update to npm v7.

  • Node:

    • LTS: 14.16.0 (includes npm 6.14.11)
    • Current: 15.10.0 (includes npm 7.5.3)

Though node use npm v7 as the current version, the majority will be using npm v6 in 2021. Consider the population, asking user to update to npm v7 adds a new pre-requisite.

Ref

0%