Monday, September 21, 2015

Clean Code



Book Review: Clean Code
Small.
Functions and classes should be small (no, even smaller than that).

Niladic and monadic functions.
The fewer arguments a function takes, the better (a niladic function takes zero arguments, a monadic  one, and a dyadic two).

Flag arguments. A flag argument to a function is a boolean argument  that controls what should be done. This is really an indication that the function should be split up in smaller parts.

http://www.techug.com/let-others-understand-your-code
“复杂的代码往往都是新手所写,只有经验老道的高手才能写出简单,富有表现力的代码”
  1. 让别人能读懂的代码
  2. 可扩展的代码
  3. 可测试的代码(代码应该具备可测试性,对没有可测试性的代码写测试,是浪费生命的表现)
其中2,3点更多强调的是面向对象的设计原则。而本文则更多关注于局部的代码问题,本文通过举例的方式,总结平时常犯的错误和优化方式。
本文的例子基于两个指导原则:
一.DRY(Don’t repeat yourself)
此原则如此重要,简单来说是因为:
  • 代码越少,Bug也越少
  • 没有重复逻辑的代码更易于维护,当你修复了一个bug,如果相同的逻辑还出现在另外一个地方,而你没意识到,你有没有觉得自己很冤?
二.TED原则
  • 简洁(Terse)
  • 具有表达力(Expressive)
  • 只做一件事(Do one thing)
三.举例说明
1.拒绝注释,用代码来阐述注释
良好的代码命名完全可以替代注释的作用,如果你正在试图写一段注释,从某种角度来看,你正在试图写一段别人无法理解的代码。
当你无法为你的方法起一个准确的名称时,很可能你的方法不止做了一件事,违反了(Do one thing)。特别是你想在方法名中加入:And,Or,If等词时
2. 为布尔变量赋值
3.双重否定的条件判断
反例:
 if (!isNotRemeberMe)
{

 }
重构后:
if (isRemeberMe)
{

}

4.拒绝HardCode,拒绝挖坑
反例:
if (carName == "Nissan")
 {

}
重构后:
if (car == Car.Nissan)
{

 }
既然咱们玩的是强类型语言,咱就用上编译器的功能,让错误发生在编译阶段
5.拒绝魔数,拒绝挖坑
所谓魔数(Magic number)就是一个魔法数字,读者完全弄不明白你这个数字是什么,这样的代码平时见的多了
6.复杂的条件判断
反例:
            if (job.JobState == JobState.New
                || job.JobState == JobState.Submitted
                || job.JobState == JobState.Expired
                || job.JobTitle.IsNullOrWhiteSpace())
            {
                //....
            }
重构后:
            if (CanBeDeleted(job))
            {
                //
            }        

        private bool CanBeDeleted(Job job)
        {
            var invalidJobState = job.JobState == JobState.New
                                  || job.JobState == JobState.Submitted
                                  || job.JobState == JobState.Expired;
            var invalidJob = string.IsNullOrEmpty(job.JobTitle);

            return invalidJobState || invalidJob;
        }
有没有豁然开朗的赶脚?
7.嵌套判断
反例:
            var isValid = false;
            if (!string.IsNullOrEmpty(user.UserName))
            {
                if (!string.IsNullOrEmpty(user.Password))
                {
                    if (!string.IsNullOrEmpty(user.Email))
                    {
                        isValid = true;
                    }
                }
            }
            return isValid;
重构后:
if (string.IsNullOrEmpty(user.UserName)) return false;
if (string.IsNullOrEmpty(user.Password)) return false;
if (string.IsNullOrEmpty(user.Email)) return false;
 return true;
第一种代码是受到早期的某些思想:使用一个变量来存储返回结果。事实证明,你一旦知道了结果就应该尽早返回。
8.使用前置条件
反例:
            if (!string.IsNullOrEmpty(userName))
            {
                if (!string.IsNullOrEmpty(password))
                {
                    //register
                }
                else
                {
                    throw new ArgumentException("user password can not be empty");
                }
            }
            else
            {
                throw new ArgumentException("user name can not be empty");
            }
重构后:
 if (string.IsNullOrEmpty(userName)) throw new ArgumentException("user name can not be empty");
 if (string.IsNullOrEmpty(password)) throw new ArgumentException("user password can not be empty");
 //register
重构后的风格更接近契约编程,首先要满足前置条件,否则免谈。
9.参数过多,超过3个
反例:
        public void RegisterUser(string userName, string password, string email, string phone)
        {

        }
重构后:
        public void RegisterUser(User user)
        {

        }
过多的参数让读者难以抓住代码的意图,同时过多的参数将会影响方法的稳定性。另外也预示着参数应该聚合为一个Model
10.方法签名中含有布尔参数
反例:
       public void RegisterUser(User user, bool sendEmail)
        {

        }
重构后:
        public void RegisterUser(User user)
        {

        }

        public void SendEmail(User user)
        {

        }
布尔参数在告诉方法不止做一件事,违反了Do one thing
10.写具有表达力的代码
相对于命令式代码,声明性代码更加具有表达力,也更简洁。这也是函数式编程为什么越来越火的原因之一。
四.关于DRY
平时大家重构代码,一个重要的思想就是DRY。我要分享一个DRY的反例:
项目在架构过程中会有各种各样的MODEL层,例如:DomainModel,ViewModel,DTO。很多时候这几个Model里的字段大部分是相同的,于是有人就会想到DRY原则,干脆直接用一种类型,省得粘贴复制,来回转换。
这个反例失败的根本原因在于:这几种Model职责各不相同,虽然大部分情况下内容会有重复,但是他们担当着各种不同的角色。
考虑这种场景: DomainModel有一个字段DateTime Birthday{get;set;},ViewModel同样具有DateTime Birthday{get;set;}。需求升级:要求界面不再显示生日,只需要显示是否成年。我们只需要在ViewModel中添加一个Bool IsAdult{get{return ….}}即可,DomainModel完全不用变化。
五.利用先进的生产工具
以vs插件中的Reshaper为例,本文列举的大部分反例,Reshaprer均能给予不同程度的提示。经过一段时间的练习,当Reshaper对你的代码给予不了任何提示的时候,你的代码会有一个明显的提高。
追加:既然大家对拒绝注 释这个建议觉得不可行,我拿出来详细说说: 1.如果你的团队代码命名不错,代码写的还算不错,没有一些奇怪的实现方式,不妨可以尝试去掉注释试试效果。因为写注释需要成本,并且重构代码的时候往往 会忽略注释的修改,时间长了注释也不够准确,反而成了一种累赘。 2.如果你的团队代码写的丑陋不堪,命名也不规范,注释必须要有,注释再不准确也比读代码读着强些。
http://www.cnblogs.com/stoneniqiu/p/4815259.html
总结下就是整洁的代码1.职责明确,没有多余,2.减少依赖,便于维护。3.高效。

第二章  有意义的命名
 1.名副其实。 说起来很简单。选个好名字需要花时间,但省下的时间比花掉的多。注意命名,一旦有好的命名,就换掉旧的。
 2.避免误导。比如不是List类型,就不要用个accountList来命名,这样形成误导。

3.做有意的区分。
如果参数名称改为source和destination ,这个函数就会像样很多。废话都是冗余的,Variable一词 永远不应当出现在变量名中。Table一词永远不应当出现在表名中。NameString 会比 Name好吗,难道Name 会是一个浮点数不成?如有一个Customer的类,有又一个CustomerObject的类。是不是就凌乱了。

4.使用便于搜索的的名称

单个字母或者数字常量是很难在一大堆文章中找出来。比如字母e,它是英文中最常用的字母。长名胜于短名称,搜得到的名称胜于自编的名称。 窃以为单字母的名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应。

5.类名应该是名词或短语,像Customer,Account,避免使用Manager,Processor,Data或者Info这样的类名。类名不应当是动词。方法名应该是动词或动词短语,如postPayment ,deletePage或Save,属性访问、修改和断言应该根据其值来命名,并加上get,set,is这些前缀。
6.别扮可爱,耍宝,比如谁知道HolyHandGrenada 函数是干什么的,没错这个名字挺伶俐,但是不过DeleteItems或许是更好的名字。
7.每个概念对应一个词。并且一以贯之。
  在一堆代码中有Controller,又有manager,driver。就会令人困惑。比如DeviceManager和Protal-Controller之间又什么本质区别?

第三章 函数

1.函数的第一规则是要短小,第二条规则是还要更短小。
2.函数应该做一件事。做好这件事。只做这一件事。
3.尽量少的函数参数。有两个参数的函数要比一元函数的难懂。如果需要三个或者三个以上的参数应该封装成类了。
4.不要重复自己。
PS:如果一段相同的代码出现了两次,你是不是觉得自己改做些什么了。

第三章 函数

1.函数的第一规则是要短小,第二条规则是还要更短小。
2.函数应该做一件事。做好这件事。只做这一件事。
3.尽量少的函数参数。有两个参数的函数要比一元函数的难懂。如果需要三个或者三个以上的参数应该封装成类了。
4.不要重复自己。
PS:如果一段相同的代码出现了两次,你是不是觉得自己改做些什么了。

第四章 注释
 3.对意图的解释。 有时注释不仅提供了有关实现的有用信息,而且还提供了某个决定后面的意图。
5.警示,告诉别人要注意这个方法之类的。

6.放大。有的代码可能看着有点多余,但编码者当时是有他自己的考虑,这个时候需要注释下这个代码的重要性。避免后面被优化掉。

Incremental design
Robert emphasizes the importance of natural growth of designs. Big upfront designs often appear to be overengineered and too technical that does not abstract business domain on an appropriate level

http://www.devwiki.net/2015/07/08/CleanCode-Note-Object-Data/
比如,我们现在需要知道手机还有多少电量.
代码三:

1
2
3
4
5
6
public interface Battery{
    //获取以mAh为单位的总电量,
    int getTotalInmAh();
    //获取以mAh为单位的剩余电量
    int getRemainingInmAh();
}

代码四








1
2
3
4
public interface Battery{
    //获取剩余电量的百分比
    double getRemainingPrecent();
}

以上两端代码,代码四最好.我们不愿意透露更多的细节,更愿意以抽象的形态表述数据.这并不只是用接口和赋值器取值器就能做好的事情.要以更好的方式呈现对象所包含的数据.
http://www.devwiki.net/2015/06/24/CleanCode-Note-Function/
只做一件事
每个函数一个抽象层次
一个函数不应该既有抽象又有细节!

我们经常写Android的Activity时这样:








1
2
3
4
5
6
7
8
9
10
11
 protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    ToastUtil.init(this);
        
    startButton = findViewById(R.id.start_button);
    resultView= findViewById(R.id.result_view);
    startButton.setOnClickListener(this);
    resultView.setText("结果为:");
}

抛去2,3两行不说.第5行为抽象,而第7~10行为细节,这样读下来,突然发生了变化,会误入到细节之中.
不如改为下面这样:








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    ToastUtil.init(this);
        
    initView();
}

private void initView(){
    startButton = findViewById(R.id.start_button);
    resultView= findViewById(R.id.result_view);
    startButton.setOnClickListener(this);
    resultView.setText("结果为:");
}

这样只需阅读在onCreate中做了哪些事情,而不需要去知道具体怎么做的.所以一个函数应保持同一抽象层次.

标志参数(boolean值)

不要使用boolean类型的参数!!!
传入boolean类型的参数,那么该函数必定违反单一职责原则!
为何不拆分为两个函数呢?

无副作用

上面有个checkAccount()函数其实就是一个有副作用的函数!
方法名为checkAccount(),且函数值也是boolean类型的.但是它却在账户可用时做了登录操作!!!
如果不知道该函数的细节,多次调用会导致重复登陆!!!
所以函数内容一定要和函数名称相同.

分割指令与查询

函数要么做什么事,要么回答什么事情,但二者不可兼得.
函数应该修改某对象的状态或者返回该对象的有关信息.

抽离Try/Catch代码块

代码处理直接放在try..catch中,要抽离出来,另外形成函数:








1
2
3
4
5
6
7
public void deletePage(){
    try{
        deletePageAndReferences(page);
    } catch (Exception e){
        logError(e);
    }
}

处理错误就是一件事

一个函数只做一件事,处理错误就是一件事,所以错误处理要抽离单独的函数.
http://www.devwiki.net/2015/06/24/CleanCode-Note-Comments/

http://www.devwiki.net/2015/06/24/CleanCode-Note-Comments/
切记能用函数或变量就别用注释

用代码来阐述

比如以下代码:






1
2
//check to see if the employee is eligible for full benfits
if((employee.flag & HOURLY_FLAG) && (employee.age > 65))

为何不改为:






1
if(employee.isEligibleForFullBenefits())

http://www.jianshu.com/p/a9f304391133

优雅的方式:编写学习性测试。

  • 找到最基础的文档(用来给第一次使用的人看的),开始阅读文档。每读完几个的api,便开始整合完成你想要的某一个功能,写一个类的一个函数将其封装起来。
  • 完成你初步罗列出来的功能便可以开始测试,如果不需要深入理解他人的代码的话,完成所需功能即可。如果想要开发超过百行的有关代码,还是把最基础文档的api全部测试一遍好。
  • 测试:对函数分别调用,从中弄懂参数和返回值的真正意义,并以此弄清当前函数整合的所有api干了什么。
  • 测试完成后,便应该只用自己封装起来的函数来写自己旳程序。当需要调用新的api,如果这个api属于之前的某个功能,就写进那个功能对应的函数,如果是新的功能,则应该考虑写新的类、新的的函数。
Clean Code
Chapter 2: Meaningful Names
Use Intention-Revealing Names
Avoid Disinformation
Make Meaningful Distinctions
-- Distinguish names in such a way that the reader knows what the differences offer.
Use Pronounceable Names
Use Searchable Names
Avoid Encodings
-- Encoding type or scope information into names simply adds an extra burden of deciphering.
Hungarian Notation -- Don't
Member Prefixes -- don’t need to prefix member
Interfaces and Implementations
-- Don't encode the intrface like IShapeFactory; interface:IShapeFactory, instead encode the implementation: ShapeFactoryImp
Avoid Mental Mapping
-- Don't use single-letter variable names: clarity is king
Class Names
-- noun. A class name should not be a verb.
Method Names
-- verb. When constructors are overloaded, use static factory methods with names that describe the arguments.
Don’t Be Cute
Pick One Word per Concept
-- A consistent lexicon is a great boon to the programmers who must use your code.
Don’t Pun
-- Avoid using the same word for two purposes.
Use Solution Domain Names
Use Problem Domain Names
Add Meaningful Context
Don’t Add Gratuitous Context
--Shorter names are generally better than longer ones, so long as they are clear.

Chapter 3: Functions
Small!
Blocks and Indenting
Do One Thing
Sections within Functions
One Level of Abstraction per Function
Reading Code from Top to Bottom: The Stepdown Rule
Switch Statements
-- bury the switch statement in the basement of an ABSTRACT FACTORY, and never let anyone see it.
-- switch can be tolerated if they appear only once, are used to create polymorphic objects, and are hidden behind an inheritance relationship so that the rest of the system can’t see them
Use Descriptive Names
Function Arguments
Common Monadic Forms
Flag Arguments
Dyadic Functions
Triads
Argument Objects
Argument Lists
Verbs and Keywords
Have No Side Effects
-- Temporal couplings are confusing, especially when hidden as a side effect. If you must have a temporal coupling, you should make it clear in the name of the function.
Output Arguments
-- output arguments should be avoided. If your function must change the state of something, have it change the state of its owning object.
Command Query Separation
-- Functions should either do something or answer something, but not both.
Prefer Exceptions to Returning Error Codes
Extract Try/Catch Blocks
Error Handling Is One Thing
The Error.java Dependency Magnet
Don’t Repeat Yourself

http://www.cnblogs.com/leotsai/p/5096429.html
首先,如果一个程序员可以随便写注释,那么他对命名准确性和方法长度的控制就不会那么在意,写代码更随意,代码质量比不能写注释的程序员更大几率低下。
其次,代码注释只是在写代码的时候提供说明,如果读代码都依靠注释的话,那一个类被另一个类引用来引用去的就根本没法阅读了。 
所以,“写注释是为了让代码更易读”本身就是站不住脚的。
2. 控制每个方法不超过50行,用方法定义来描述方法的实现逻辑。
3. 变量命名不要太过随便。
如何写出漂亮的代码——臃肿的service
在我们的项目架构中,数据库访问通常是用entity framework(EF),另外有一个很重要的service层,主要用于跟EF交互,也会在这一层封装大部分的业务逻辑。通常情况下,我们会用一个接口将某个service的成员提出来,然后通过IOC获取该service的实现。
由于service层主要为UI层提供服务,为了让调用者直接的看到可用的方法,因此往往某个service会包含某个模块的所有方法和属性,于是这个service会变得非常庞大。举个例子,比如我们有一个IProductService,用于为product模块提供数据服务。这个product模块下面包含多个子模块,比如该product的各种统计数据,销售,订单,跟踪信息等。这样一来,这个IProductService下面就可能有30多个方法,如果将这么多的方法写到一个文件里头,那这个文件很难不超过300行代码。
读到这里,你肯定在想我们可以把这些实现的代码分成多个块。可能首先想到的,也是我们大多数程序员正在写的,那就是#region/#endregion。 其实还有另外一个方案,那就是partial class。
使用partial class来拆分我们的service,其实只是一个太简单不过的想法,但就是这个思想上简单的进步,拯救了我多少的代码。从此,我的service类非常丰富,而service的实现根据模块或者调用者角色或者其他分配到多个partial类,每一个文件不超过300行代码,让维护变得非常简单,让代码变得易读。
其实使用partial类来拆分我们的大类不仅仅是可以用于service层,而是可以用于任何地方。
我最近新加入了一个项目组,这个项目的代码写的有些糟糕,很多类超过1000行代码,很多方法200多行代码,看到这样的代码实在不想去打开编辑,更别谈读懂其业务逻辑并维护。这个项目运行了好几年了,好几批程序员写过代码,可以说这个项目被多少程序员糟蹋得不成样子了。经过简单的分析,其实主要的问题在于service层和controller层的类文件太大,于是我安排人员用partial class进行拆分。重构后的代码别提变得多清纯了,让我们这些IT男喜欢不已。
朋友,你的项目里有大类吗?试着用partial class拆分下吧,相信你会有惊喜的。
项目中有下面这样一段代码,大家看有什么问题:
复制代码
1 public class TemplateService
2     {
3         public Template Add(Template template)
4         {
5             //do save it to db
6             return template;
7         }
8     }
复制代码
 上面的代码我们可能经常都在写,好像看不出有什么问题。但我认为上面这个Add方法读起来就不通顺。如果代码是上面这么写的,那么调用的代码可能就像下面的这样:
var service = new TemplateService();
var template = new Template(){...};
template = service.Add(template);
注意到上面最后一行代码,读起来是不是非常别扭?
我认为好的代码应该是这样的:
1 var service = new TemplateService();
2 var template = new Template(){...};
3 service.Add(template);
(在Add方法体里面,可能会对template实例的某些属性进行赋值,比如ID,因此没有必要再返回template)。
其实,除了Add, 我认为还有很多方法都不应该带返回值。我可以随便列举一些非常常见的调用例子:
userService.Save(user);
userService.Update(user);
userService.Delete(user.Id);
userService.Login(user);
你可能会想,上面这些方法可以返回bool值啊。事实上,在很多代码里可以看到这些方法确实返回了bool值,甚至是有经验的程序员也在这么写。但我并不认为这是一种好的做法。对于那些返回bool值的方法(无非就是想告诉调用者方法是否执行成功),我认为应该用抛出异常的方式来处理。这样做有多个好处:
  1. 可以根据输入抛出多个不同的异常信息,而不是将异常吃掉,只是返回一个简单的true/false。
  2. 调用处的代码读起来更通顺。
对于某些方法如果你确实不想抛出详细的异常信息,只想告诉调用者成功与否,也就是说你的方法体里面自己会处理异常,那么我建议给方法名称加前缀“Try”. 然后你的代码就会变成这样:
var success = userService.TryLogin(username, password);
上面这段代码就告诉调用者不用处理异常了,因为service里面已经有try/catch了。如果使用抛出异常的模式,我也简单写个例子吧:
 1 public void Login(username, password){
 2     var user = Get(username);
 3     if(user == null){
 4         throw new Exception("The user doesn't exist");
 5         // throw new UserNotExistException();
 6     }
 7     if(user.Password != EncodePassword(password)){
 8         throw new Exception("Incorrect password!");
 9          // throw new PasswordDosntMatchException();
10     }
11     // do other logic
12 }
http://www.cnblogs.com/leotsai/p/how-to-write-beautiful-query-code.html
 5         public PagedResult<OrderDto> Search(OrderSearchCriteria criteria, PageRequest page)
 6         {
 7             PagedResult<OrderDto> result;
 8             using (var db = new DemoDbContext())
 9             {
10                 result = db.Orders
11                     .WhereByDealerId(criteria.DealerId)
12                     .WhereByStatus(criteria.Status)
13                     .WhereByProductType(criteria.ProductTypeId)
14                     .WhereByNumber(criteria.OrderNumber)
15                     .WhereByKeyword(criteria.Keyword)
16                     .WhereByFromDate(criteria.FromDate)
17                     .WhereByToDate(criteria.ToDate)
18                     .WhereByFromCost(criteria.FromCost)
19                     .WhereByToCost(criteria.ToCost)
20                     .ToOrderDtos()
21                     .PageTo(page);
22             }
23             return result.BuildDealerInfo()
24                 .BuildProductInfo()
25                 .BuildCustomerInfo()
26                 .BuildReceiver();
27         }
28     }

  • WhereBy过滤的代码放到实体类扩展里面,跟实体类(domain层)的定义放在同一个程序集,挨着实体类定义。上面的例子中,放到OrderExtensions类里面。
  • DTO类定义在service层,非domain层。ToOrderDtos()放在dto扩展类里面。上面的例子中,放到OrderDtoExtensions类里面。
  • PageTo属于IQueryable<T>的扩展,放到infrastructure层。
  • Build放到service层,DTO扩展代码里面。
http://www.cnblogs.com/leotsai/p/our-ultimate-coding-standards.html
  1. 每一个文件夹不能超过30个文件和子文件夹,对于架构而言;
  2. 业务相关的代码一定要放到一起;
  3. 尽可能降低各个类的耦合度;
  4. 写任何代码,当性能不是问题的时候,都应该把代码写的更易读。
命名要准确,不可模糊。不能因为命名太长而选择有歧义或模糊意义的命名。比如以前项目中的一个案例:数据库中有一个“Recipe(菜)”表,做这个菜的时间包含:PrepareTime, CookTime, OvenTime, CleanTime。这里的命名有问题,因为调用者不知道这里Time是存的秒还是分还是带小数的小时,于是改成:PrepareMinutes, CookMinutes, OvenMinutes, CleanMinutes。另一个常见例子是,单词“interval”用作命名的时候,调用者也不清楚是分钟还是毫秒,于是后面都要加单位。

Bool类型返回值的方法,除了is做前缀外,还有can, will, does, has, should。以前在项目中看到一个方法,叫IsReceiveMessage,我在想是不是IsReceivingMessage,因为很多国内程序员英语语法不好,但后面我看到注释才发现,这个方法实际上是判断用户是否能收到短信,也就是说这个方法应该叫CanReceiveMessage。我相信写这个方法的程序员,写完这个方法命名时,肯定自己读着也感觉不太懂,所以加了个注释。实际上所有加注释的地方,要么命名不准确,要么方法太长。一旦你发现自己在写注释,那么你就需要思考这2个问题了。
 3     public class UserService : IUserService
 4     {
 5         public void UpdateByAdmin(User user, int[] roleIds)
 6         {
 7             using (var db = new DemoDbContext())
 8             {
 9                 var dbUser = db.Users.Get(user.Id);
10                 if (dbUser == null)
11                 {
12                     throw new Exception("The user doesn't exist.");
13                 }
14                 if (!dbUser.Username.Eq(user.Username))
15                 {
16                     if (db.Users.Exists(user.Username))
17                     {
18                         throw new Exception("The username is already taken.");
19                     }
20                 }
21                 dbUser.UpdateByAdmin(user);
22                 dbUser.UpdateRoles(roleIds, db);
23                 db.SaveChanges();
24             }
25         }
26     }
  • 第1步,从数据库获取实体类实例;
  • 第2步,判断是否为空,抛异常;
  • 第3步,检查其他数据,抛异常;
http://www.cnblogs.com/leotsai/p/live-screen-demo-of-programming.html

Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts