Skip to content

Software Development Tips

以套件實現系統功能的優先順序考量

  1. 系統套件
  2. 第三方開源套件
  3. 自己修改過的第三方套件
  4. 自己刻的套件

Semantic Versioning 語意化版本

  • Semantic Versioning: MAJOR.MINOR.PATCH
    • MAJOR: when making incompatible changes.
    • MINOR: when adding functionality in a backward compatible manner.
    • PATCH: when making backward compatible bug fixes.

License

Naming

  • flatcase
  • camelCase, lowerCamelCase, dromedaryCase
  • StudlyCase, UpperCamelCase, CapitalCamelCase, BumpyCase, PascalCase
  • kebab-case, dash-case, hyphen-case, param-case, caterpillar-case, spinal-case, brochette-case, css-case, lisp-case
  • Train-Case
  • COBOL-CASE
  • snake_case, pothole_case, c_case
  • MACRO_CASE, ALL_CAPS, UPPER_CASE, SCREAMING_SNAKE_CASE

Expression v.s. Statement

Expression v.s. Statement

  • expression: any section of codes evaluating to a value.
  • statement: a complete line of code performing some actions, without a value returned.

Object-Oriented Programming

  • High cohesion, low coupling.
  • Not Encapsulation, Inheritance or Polymorphism, but Abstraction to deal with complexity easily.
  • Write Everything Twice -> Don't Repeat Yourself.
  • SOLID by Robert. C. Martin for OOP clean code design
    • Single responsibility principle(單一功能原則): A software entity(module, class, function) should have one, and only one, reason to be changed.
      • Responsibility is a "reason to change".
    • Open-closed principle(開閉原則): A software entity should be opened for extension, but closed for modification.
      • When a new feature needs to be built inside it, extend the entity instead of modifying it.
    • Liskov substitution principle(里氏替換原則): Derived classes must be substitutable for their base classes.
      • a.k.a. Behavioral Subtyping.
      • The signature, return type and exception types of a method must be same in base class and its derived classes.
    • Interface-segregation principle(介面隔離原則): Many client-specific interfaces are better than one general-purpose interface.
      • Role Interface: make fine grained interfaces that are client-specific.
    • Dependency inversion principle(依賴反轉原則): Use Dependency Injection to decouple software modules.
      • High-level modules shouldn't depend on low-level modules. Both should depend on abstractions.
        • Depend on abstractions, not on concretions.
      • Abstractions shouldn't depend on details. Details should depend on abstractions.

SOLID - Dependency Inversion Principle

Architectures

"The only way to go fast, is to go well." — Robert C. Martin

  • The Clean Architecture
  • Hexagonal(六角形) Architecture: Ports(interfaces) & Adapters(implementations)
    • Android Modularization: Hexagonal Architecture with Kotlin and MVVM
    • Pros: Testability & Maintainability, because of more modularity.
    • Cons: Complexity, because of more time-costing built artifacts when the application is bigger.
  • Screaming Architecture
  • The Onion Architecture
    • Separation of concerns: The application codes are separated into layers.
      • Entities: Enterprise Business Rules, business objects of the application.
      • Use Cases: Application Business Rules
        • Ports & Interactors
        • Orchestrate the data flow to and from the Entities, and direct them to use their enterprise wide business rules to achieve the goals of the use case.
      • Interface Adapters: Controllers, Presenters & Gateway
        • Convert data from the format which is most convenient for the use cases and entities, to the format which is most convenient for some external agencies.
        • ex. MVC architecture of a GUI.
      • Frameworks & Drivers: External Interfaces, UI, Web Framework or API, Devices & DB
    • Dependency rules
      • Dependency points inward, each layer only interacts with the layers inside it.
      • Concrete modules depend on the more abstract ones.
    • More bottom/inner, more generic/abstract
      • Implementation details(mechanisms) -> policies & rules.

Unit Testing

  • A small piece of code that applies input to a component under testing and then asserts expectations.
  • What are properties of good Unit Testing?
    • run fast: for big scale input and fast feedback loop while coding.
    • small and focus: test only one piece of logic every time without any control flow or iteration in it.
    • isolated: states when each test ends should be same as their beginning.
    • trustworthy: developers in your team need to trust the test.
    • readable and maintainable: follow coding style.
    • automated: use frameworks in IDE or CI.
  • 2 types
    • State-based: result-driven, black-box, ex. JUnit
      • input -> component under testing -> output
    • Interaction-based: action-driven, white-box, ex. Mockito
  • 3A rule
    • Arrange: 設置環境 -> Given
    • Act: 動手做實驗 -> When
    • Assert: 驗證 -> Then
  • Test Naming: methodOrClassUnderTest_actionOrInput_expectedResult

Test Doubles 測試替身

  • 搞笑談軟工:什麼是測試替身?
  • A version of a class crafted specifically for testing, replacing its real version in tests.
    • Fake: a "working"(producing realistic outputs when given inputs) implementation of the class to make it good for testing but unsuitable for production.
    • Mock: tracks which of its methods were called, then the test passed or failed depends on whether these methods were called correctly.
    • Spy: tracks some additional information of its methods, such as the number of calling a method.
    • Stub: includes no logic and only returns what you program it to return.
    • Dummy: passes around but not used, such as if you just need to provide it as a parameter.
  • To avoid flaky(易碎成小薄片的) tests: test cases with inconsistent results when run repeatedly on the same test code.

Test Driven Development

  • Write tests first, write enough feature code to pass the tests, and refactor the feature code better and able to pass them as well.
  • To protect your feature code from ever accidentally reintroducing bugs of the feature in the future.