Upload
aftership
View
148
Download
0
Embed Size (px)
Citation preview
How to code better and fasterBy Vimukthi
Overview
● Lets define ‘better’● Key principles in software architecture
Foreach (principle in key_principles) { ❏ The principle❏ How to follow the principle.❏ Code demonstration/workshop
}● Design patterns summary● References● Q&A
Question :What is better
?
● Quality● Fast time to market● Readability● Easy to Change/Adapt● Etc.
Key principles in software architecture
● Separation of concerns● Single responsibility Principle● Principle of least knowledge● Don’t repeat yourself(DRY)● Minimize up front design(YAGNI)
Maintainability=Better
Time to market=Faster
How to Balance Maintainability vs Time to market?
Answer:
Follow this Presentation without falling asleep :D
Key principles in software engineering
Separation of concerns● Divide app into layers of non overlapping concerns● Minimize interaction points between the layers● High cohesion + Low Coupling
Question : Identify mixed up architectural concerns in following code?
source: http://cwbuecheler.com/web/tutorials/2014/restful-web-app-node-express-mongodb/
Specific Answer - separate the data handling code
Any other problems you see?
General Answer - Follow a layered architecture pattern such as MVC, DAO, DDD upfront
MVCDDD
DAO
Aftership Notice Board
● Aftership needed an online notice board and some guy at Aftership built this app
● Now he has left. We need to add a few new features
● But no one but him understands the code :(● So we need your help in making it more
maintainable
1) Time For Some Exercise :)● Clone the repository https://github.com/vimukthi-git/howtcodebetterfaster/● This is using Koa framework http://koajs.com/ ● ‘npm install ’● Run the app with ‘npm start ’ and open ‘http://localhost:3000 ’● For a start checkout the branch ‘1_separate_concerns_bad ’● Open the app in your IDE● Check the ‘app.js’, Seems the entire app is in one file now.● Let’s separate the concerns by following MVC. ● Extract the handlers and their dependencies into a ‘controllers.js ’.
Fully MVC version is in the branch ‘2_separate_concerns_good’
Key principles .. cntd,
Single responsibility Principle
● A responsibility is “a reason to change”● Divide components so that each one will only “change” for a
single reason only● Write side-effectless code
Question : Separate the responsibilities of following class?
Specific Answer - Divide Auth, Detail, Orders, Request into separate modules
General Answer - Follow Module or a composition pattern depending on the situation
● Divide to class and files like we did in the example - Module Pattern● Microservices pattern derives from this● Follow a composition pattern such as chain of control or strategy,
2) Let’s refactor our app so that controllers have single responsibility
● After we converted the app to MVC it was easier for us to add our user login feature.
● Checkout the branch ‘3_single_responsibility_bad ’, Run the app● Login user: ‘vimukthi ’ pass: ‘123’● But seems our controller violates single responsibility● Let’s create a directory ‘controllers ’ and add two new files
‘auth_controller.js ’ and ‘notice_controller.js ’● Move login related handlers and their dependencies to ‘auth_controller.
js’
Fully single responsibility version is in the branch ‘4_single_responsibility_good’
Chain of control pattern
Where have you seen chain of control pattern?
3) Let’s practice chain of control
● Add the config.json with an auth parameter for local, dev prod envs● Load the config in app.js● Provide the config to controllers in a koa middleware (Note this is
just an example, There is a better way to do configs in Koa)● Use the config in auth controller to remove authentication for local
env● As you can see koa middleware is a great example of chain of
control pattern
Answer is in the branch ‘5_chain_of_control’
Strategy pattern
4) Let’s practice strategy pattern
● Right now the notice board sorts by chronological order only● Let’s make it sort by alphabetical order while also making good use of strategy
pattern.● Let’s extract query parameter ‘sort’ in the
`controllers/notice_controller`● Then add a `sort` parameter to ‘list’ function in
`models/notice_model.js ` ● Then add the two strategy classes for sorting in ‘utils.js ’● Refactor `list` function to take the sort parameter and use the strategy
classes to sort.
Answer is in the branch ‘6_strategy’
Key principles .. cntd,
Principle of least knowledge
● Each unit should have only limited knowledge about other units:
● Each unit should only talk to its friends; don't talk to strangers.
● Only talk to your immediate friends.
Question : Why does following code violate Principle of least knowledge?
source: https://github.com/AfterShip/aftership-sdk-nodejs
Specific Answer - Define proper interfaces and hide implementation
source: https://github.com/AfterShip/aftership-sdk-go
● Define proper interface methods● Hide REST specific parts in interface● Separate implementation and interface if
possible● Specify types of variables in interface if
possible● Help the lang interpreters/compilers in
helping the user● Only use Libs that hide implementation
details
General Answer - Use clear interfaces● Javascript(Nodejs) has no interfaces, so better to document well, follow a
convention or implement programmatic type/interface checking.● Somehow prevent the people who use your code from depending on the
internals.
5) Exercise Add a new data model
● To better understand the concept of an interface we will now add a new data model to our app
● This model will use the file system as the data store instead of the JS array our current model uses
● First copy the ‘models/notice_model.js’ to a new file in the model directory called ‘models/notice_file_model.js’ .
● Then add a ‘notices.json ’ file with array of notices to the root of project● Rewrite the `list` and `getById` functions to load from json file● Then add a function called ‘saveToFile(message, noticesJson)’● Save to json file when `create` is called
Answer is in the branch ‘7_add_new_data_model’
General Answer - Private class data pattern
source: http://www.2ality.com/2016/01/private-data-classes.html
6) Exercise convert user model to use Private class data pattern
● Let’s make our User object variables such as username private.● Introduce `Symbol` s for `username` and `password` variables.● Define private variables for them based on symbols● Finally add getters● Advantage is we can easily switch to using email as the user name if we
wanted
Answer is in the branch ‘8_private_class_data’
General Answer - Dependency injection pattern
Who ever creates SayHelloWithStrategy instances has to wire the dependencies. SayHelloWithStrategy is oblivious to the way its strategies are created.
We already covered another good example in our app for dependency injection, can you name it?
Key principles .. cntd,
Don’t repeat yourself
● Specific functionality should be implemented in only one component
● Then reused
Question : How to create a MurderRobotDog with following class hierarchy?
source: https://www.youtube.com/watch?v=wfMtDGfHWpA
Specific Answer : Instead of creating a hierarchy, create objects/functions that provide the needed functionality and compose the final solution
source: https://www.youtube.com/watch?v=wfMtDGfHWpA
I.e We prevent our code from violating DRY by reusing almost all code we write.
General Answer : Use composition instead of inheritance
● Define all functionality using smaller single responsibility functions in a stateless and side effectless manner.
RetrieveJob
● Then you can combine them to build more complex functions easily.
● This is essentially like using Lego blocks to construct a building
ExecuteJob
ReputJob
ProcessJob
RetrieveJob ProcessJob
RetrieveJob ExecuteJob
ReputJob
General Answer : Use composition instead of inheritance
Eg: Strategy Pattern
7) Let’s practice basic composition to add a render util to our controllers
● No need of inheritance anywhere in our app as we reuse and model our code based on composition
● Render method is a great example of how we can demonstrate this.● In a traditional MVC app there would be a Generic/Parent controller so that
other controllers can inherit all methods● But we will make all those methods into utils in ‘utils.js ’
Answer is in the branch ‘9_basic_composition’
Key principles .. cntd,
Minimize upfront design
Question : How to better Balance Maintainability vs Time to market?
Answer: Do not reinvent the wheel of good software design
● Follow tried and tested design patterns● Following patterns makes it easy to build frameworks/automate● Using patterns build independent functions/modules with,
○ Separated concerns and good interfaces○ Well defined responsibilities ○ And reusability in mind
● Prefer composition over Inheritance as○ It minimizes the need to think about object hierarchies upfront○ It makes your architecture as well as your product more agile
● Refactor continuously
Patterns Summary
● Model-View-Controller(or Model-View-*)● Data Access Objects● Module Pattern● Chain of Responsibility Pattern● Strategy Pattern● Private Class Data Pattern● Dependency Injection Pattern
References
● Gang of Four - https://books.google.com.hk/books/about/Design_Patterns.html?id=6oHuKQe3TjQC&source=kp_cover&redir_esc=y
● Key architecture concerns - https://msdn.microsoft.com/en-us/library/ee658124.aspx
● Agile Architecture - http://www.scaledagileframework.com/agile-architecture/
Q & A
Thanks..!