My Coding Philosophy/ enterprice programming 101 / by Nima Shokouhfar

In this mind map, I outline my coding philosophy, focusing on key principles like scalability, dependency control, reliability, and agility. You'll see how I prioritize modularity, reusability, and extensibility in my approach to software development. The mind map breaks down essential concepts such as microservices, domain-driven design, CI/CD, and how to embrace failure to build future-proof systems. Explore the map to gain insights into my development strategy and how I create systems tha...

Get Started. It's Free
or sign up with your email address
My Coding Philosophy/ enterprice programming 101 / by Nima Shokouhfar by Mind Map: My Coding Philosophy/ enterprice programming 101 / by Nima Shokouhfar

1. mono repo

2. single source of truth

2.1. database

3. event driven design

3.1. cqrs

3.2. saga

3.3. data redundancy

4. ci cd

5. patterns

5.1. Repository

5.2. unit of work

5.3. Saga pattern

5.4. Specification pattern

5.5. Fluent API

5.6. Mediator

5.7. chain of responsibility

5.8. observer

5.9. Template method

5.9.1. Main

6. Code Smells

6.1. Bloaters

6.1.1. Long Method

6.1.2. Primitive Obsession

6.1.3. Data Clumps

6.1.4. Large Class

6.1.5. Long Parameter List

6.2. Object-Orientation Abusers

6.2.1. Alternative Classes with Different Interfaces

6.2.2. Refused Bequest

6.2.3. Switch Statements

6.2.4. Temporary Field

6.3. Change Preventers

6.3.1. Divergent Change

6.3.2. Parallel Inheritance Hierarchies

6.3.3. Shotgun Surgery

6.4. Dispensables

6.4.1. Comments

6.4.2. Data Class

6.4.3. Lazy Class

6.4.4. Duplicate Code

6.4.5. Dead Code

6.4.6. Speculative Generality

6.5. Couplers

6.5.1. Feature Envy

6.5.2. Incomplete Library Class

6.5.3. Middle Man

6.5.4. Inappropriate Intimacy

6.5.5. Message Chains

6.5.5.1. In code you see a series of calls resembling a->b()->c()->d()

6.5.5.1.1. Reasons for the Problem

7. styles

7.1. bad

7.2. good

7.3. not as good

7.4. not as bad

7.5. important

7.6. warning

8. API first approach

8.1. modern

8.2. Traditional "code-first"

8.2.1. development can result in delays, rework, and a disjointed developer experience due to late API integration.

8.3. API-first design

8.3.1. It prioritizes the API's creation before the main application, promoting better cohesion and future integrations.

8.3.2. API-first methods align with agile practices,

8.3.2.1. allowing early stakeholder feedback and design adaptability.

8.3.3. API-first development emphasizes making functionalities available as APIs initially,

8.3.3.1. ensuring stability and predictability.

8.3.4. API-first design involves thorough planning before building the API,

8.3.4.1. focusing on functionality, scalability, and developer experience.

8.3.5. Hiram's Law

8.3.5.1. "With a sufficient number of users of an API, it does not matter what you promise in the contract; all observable behaviors of your system will be depended on by somebody."

8.3.5.2. highlights the challenge of separating interface from implementation

8.3.5.3. the importance of understanding consumer reliance.

8.3.5.4. in simple form

8.3.5.4.1. If many people use a tool (like an API), they'll use it in ways you didn't always expect.

8.3.5.4.2. They'll come to rely on both what you officially tell them (documented features) and things they discover themselves (undocumented behaviors).

8.3.5.4.3. If you change any part of that tool, even the undocumented parts, you might break how they use it.

8.3.5.4.4. This means when making tools for others, you need to be careful about changes and think about all the ways users might have adapted to the tool's behaviors.

9. Objective

9.1. in a nutshell

9.1.1. create a system that can pass the test of time

9.1.1.1. scalability

9.1.1.2. dependency control

9.1.1.3. reliability

9.1.1.4. reusability

9.1.1.5. extensibility

9.1.1.6. interprobabibility

9.1.1.7. standardization

9.1.1.8. being agnostic

9.1.1.9. low barrier to entery, high celling

9.1.1.10. be agile

9.1.1.10.1. refactoring

9.1.1.10.2. iteration

9.1.1.11. business side

9.1.1.11.1. transparency

9.1.1.11.2. network effect

9.1.1.11.3. gamification

9.1.1.11.4. ikea effect

9.1.1.11.5. build for publicity

9.1.2. since failure is inevitable, let's embrace it

9.2. detail

9.2.1. Scalability

9.2.1.1. example

9.2.1.1.1. micoservices

9.2.1.1.2. domain driven design DDD

9.2.1.1.3. Event driven design EDD

9.2.1.1.4. dependency injection

9.2.1.1.5. factory patterns

9.2.1.1.6. command query responsibility query CQRS

9.2.1.1.7. cloud

9.2.1.1.8. Test driven development

9.2.1.1.9. solid principles

9.2.1.1.10. CI CD

9.2.1.1.11. infrastructure as code

9.2.2. Dependency control

9.2.2.1. decoupling

9.2.2.1.1. service decoupling

9.2.2.1.2. data decoupling

9.2.2.2. example

9.2.2.2.1. dependency injection

9.2.2.2.2. Domain driven design

9.2.2.2.3. event driven design

9.2.2.2.4. solid principles

9.2.3. Maintainability

9.2.3.1. single source of truth

9.2.3.2. solid principles

9.2.3.3. test driven development

9.2.3.4. back compatibility matters

9.2.3.5. issues

9.2.3.5.1. if your employee resign would you die?

9.2.3.5.2. if your supplier could not supply you, would you die?

9.2.3.5.3. Can you continue the business forever?

9.2.4. reliability

9.2.4.1. automated test

9.2.4.2. ci cd

9.2.4.3. infrastructure as a code

9.2.4.4. Why?

9.2.4.4.1. how reliable is your system?

9.2.4.4.2. Is it full of bugs?

9.2.4.4.3. can you catch bugs before you ship?

9.2.5. interprobability

9.2.5.1. open portocols

9.2.5.2. plugin systems

9.2.5.3. Why?

9.2.5.3.1. Is your product can talk to other products or services?

9.2.6. reusability

9.2.6.1. example

9.2.6.1.1. Domain driven design

9.2.6.1.2. Solid principles

9.2.6.1.3. microservices

9.2.6.2. Why?

9.2.6.2.1. Can you reuse the code?

9.2.6.2.2. Or should you reinvent the wheel everytime you face an exact same issue?

9.2.6.2.3. Can you leverage past for the future?

9.2.7. standardization

9.2.7.1. follow standards

9.2.7.2. not reinventing the wheel

9.2.7.3. repeatability of the patterns

9.2.7.4. Why?

9.2.7.4.1. Why to reinvent the wheel, if someone else has done it before?

9.2.7.4.2. muscle memory

9.2.8. extensibility

9.2.8.1. example

9.2.8.1.1. plugin systems

9.2.8.2. Open close principle

9.2.8.3. Why?

9.2.8.3.1. can you build a code that could be easily upgraded without impacting existing codes

9.2.8.3.2. ship first develop later

9.2.9. being agnostic

9.2.10. low barrier to entery, high celling

9.2.11. be agile

9.2.11.1. refactoring

9.2.11.2. iteration

10. Solid principles

10.1. Principles

10.1.1. Interface Segregation Principle

10.1.1.1. description

10.1.1.1.1. Client should not be forced to implement an interface that it will never use or interface that is irrelevant to it.

10.1.1.2. good link

10.1.1.3. example

10.1.1.3.1. problem

10.1.1.3.2. Solution

10.1.1.4. example 2

10.1.1.4.1. seperate online payment from offline payment

10.1.1.5. Advantages

10.1.1.5.1. By implementing smaller interfaces we are able to separate responsibilities

10.1.1.5.2. By implementing smaller interfaces we are able to distribute responsibilities among multiple interfaces and thus achieve abstraction.

10.1.1.5.3. Classes can use relevant interfaces and thus implement functions that are required by the classes. So we are able to keep the class clean by keeping out code that is of no use to the class.

10.1.2. Liskov Substitution Principle

10.1.2.1. description

10.1.2.1.1. Any function or code that use pointers or references to base class must be able to use any class that is derived from that base class without any modifications

10.1.2.2. All implementation of a interface should be perfectly implemented and swappable

10.1.2.2.1. This principle suggests that you should write your derived classes in such a way that any child class (derived class) should be perfectly substitutable in place of its parent class (base class) without changing its behaviour.

10.1.2.3. In short

10.1.2.3.1. all drived classes should give the same output for the given input.

10.1.2.3.2. a fact

10.1.2.4. Link much better explanation

10.1.2.4.1. If substituting a superclass object with a subclass object changes the program behavior in unexpected ways, the LSP is violated.

10.1.2.4.2. Why this is an issue?

10.1.2.4.3. How to Identify LSP Violations?

10.1.2.5. example

10.1.2.5.1. example 1

10.1.2.6. Advantages

10.1.2.6.1. Makes subclasses swappable

10.1.3. Open Close Principle

10.1.3.1. description

10.1.3.1.1. A software class or module should be open for extension but closed for modification

10.1.3.2. If we have written a class then it should be flexible enough that

10.1.3.2.1. we should not change it (closed for modification) until there are bugs

10.1.3.2.2. but a new feature can be added (open for extension) by adding new code without modifying its existing code.

10.1.3.3. This principle says that it should be possible to extend functionality in classes without modifying the existing code in the classes

10.1.3.3.1. it should be possible to extend the behaviour of the software without modifying its core existing implementation.

10.1.3.4. implementation

10.1.3.4.1. By open for extension

10.1.3.5. example

10.1.3.5.1. how to do it wrong

10.1.3.5.2. correct approach

10.1.3.6. Advantages

10.1.3.6.1. loose coupling

10.1.3.6.2. Avoid modification of existing code

10.1.4. Single Responsibility Principle

10.1.4.1. description

10.1.4.1.1. Each software module or a class should have one and only one reason to change

10.1.4.1.2. it performs one single task

10.1.4.2. Example

10.1.4.2.1. What not to do

10.1.4.2.2. solution

10.1.4.3. Why not?

10.1.4.3.1. If you add more than one responsibility or task into a single class then we end up with TIGHTLY COUPLED functionalities that should have not been together

10.1.4.3.2. This is difficult to maintain as a change in one functionality might impact other functionality.

10.1.4.3.3. this is against atomic design

10.1.4.4. Advantages

10.1.4.4.1. Reusability

10.1.4.4.2. Improve maintainability by Minimizing data coupling impact

10.1.4.4.3. Improves testability

10.1.4.4.4. Minimize modification

10.1.4.4.5. seperation of concerns

10.1.4.4.6. easier design and implement

10.1.4.4.7. readability

10.1.4.4.8. easier debuging

10.1.4.5. Summary

10.1.4.5.1. By using the single responsibility principle we can reduce dependency between functionalities and hence can better manage our code for implementing new features over the long run.

10.1.5. Dependency Inversion Principle

10.1.5.1. description

10.1.5.1.1. High level classes should not depend on low level classes instead both should depend upon abstraction.

10.1.5.1.2. Abstraction should not depend upon details infact details should depend upon abstraction

10.1.5.1.3. This principle suggests that there should be loose coupling between high-level and low-level classes and to achieve this loose coupling components should depend on abstraction.

10.1.5.1.4. names

10.1.5.2. example

10.1.5.2.1. example 1

10.1.5.3. Advantages

10.1.5.3.1. Make the code more testable

10.1.5.3.2. we can mock interfaces easily

10.1.5.3.3. implementations become swappable

10.1.5.3.4. Classes depend on abstraction and not on concrete types

10.1.5.3.5. High-level and low-level classes are loosely coupled

10.1.5.3.6. As long as you are not changing contracts change in one class will not trigger a change in another class

10.1.5.3.7. Since classes depend on abstraction change in one class will not break another class

10.2. why

10.2.1. maintenance

10.2.1.1. as a result, you need to modify the code

10.2.1.2. example

10.2.1.2.1. add features

10.2.1.2.2. fix bugs

10.2.1.3. The design of the solution should be such that it should be easy to modify or extend existing code

10.2.2. scalability

10.2.3. reusability

10.3. Solution

10.3.1. implement code such that you are able to make a design with considerations for

10.3.1.1. flexibility

10.3.1.2. extendibility

10.3.1.3. readability

10.3.1.4. maintainability

10.4. link

11. This principle simply says that you should introduce abstraction between high-level and low-level classes that allows us to decouple the high-level and low-level classes from each other.

11.1. If classes depend on each other then they are tightly coupled to each other.

11.1.1. When classes are tightly coupled then change in any one class triggers changes in all other dependent classes as wel

11.1.2. Instead, low-level classes should implement contracts using an interface

11.1.3. high-level classes should make use of these contracts to access concrete types

12. setters & getters

12.1. Why?

12.1.1. You want to have a gateway to control the access to properties

12.1.1.1. application examples

12.1.1.1.1. logging

12.1.1.1.2. validation

12.1.1.1.3. debugging

12.1.1.1.4. authorization

12.1.1.1.5. state control

12.1.1.1.6. add event

12.1.2. avoid redefinition of a property

12.1.2.1. Setting a variable directly gives control to outside code like

12.1.2.2. code

12.1.2.3. Solution

12.1.2.3.1. So, using getters and setters will give the control with our class instance and not other possible bad class.

12.1.3. easy relocation of data

12.1.3.1. Maybe in the original code, accessing data directly could be ok

12.1.3.2. However, based on requirements you may want to relocate the data to a database, file, or cache

12.1.3.2.1. if you access the data directly this will be very difficult

12.1.4. Legacy codes without setter and getters are extremely unmaintainable

13. abstraction / interfaces

13.1. Why we do abstraction?

13.1.1. enable some well know patterns

13.1.1.1. plugin systems

13.1.1.2. Decorator

13.1.1.3. chain of responsibility

13.1.2. to ship first and develop later

13.1.3. TDD

13.1.3.1. Write test first and implement later

14. dependency control

14.1. god objects

14.2. object drilling

14.3. dependency injection

15. domain driven design

15.1. uncle bob clean architecture

15.1.1. objective

15.1.1.1. the separation of concerns

15.1.1.1.1. this is done by dividing the software into layers

15.1.2. The Dependency Rule

15.1.2.1. The concentric circles represent different areas of software

15.1.2.1.1. The outer circles are mechanisms

15.1.2.1.2. The inner circles are policies.

15.1.2.2. This rule says that source code dependencies can only point inwards.

15.1.2.2.1. Nothing in an inner circle can know anything at all about something in an outer circle

15.1.2.2.2. data formats used in an outer circle should not be used by an inner circle

15.1.2.3. LAYERS

15.1.2.3.1. Entities

15.1.2.3.2. Use Cases

15.1.2.3.3. Interface Adapters

15.1.2.3.4. Frameworks and Drivers.

15.1.3. Styles

15.1.3.1. bad

15.1.3.2. good

15.1.3.3. not as good

15.1.3.4. not as bad

15.1.3.5. important

15.1.3.6. warning

16. tdd

16.1. why

16.1.1. automated test

16.1.1.1. especially, for multiple instances of same class

16.1.1.2. plugin systems

16.1.1.3. Sometimes, it is faster to test a functionality by automated tests than doing it manually

16.1.2. catch bugs that are extremely difficult to create manually

16.1.3. refactoring

16.1.3.1. When changing the code, you do not create a time bomb

16.1.3.1.1. this means catch the possible bugs by tested that where developped before

16.1.4. Maintenance

16.1.4.1. Passing to other engineers

16.1.5. Performance testing

16.1.5.1. Execution time testing