【第1324期】如何像个程序员一样思考

598 阅读13分钟
原文链接: mp.weixin.qq.com

前言

转行或刚入门的童鞋可以看看。今日早读文章由@PeterZ分享。

@PeterZ,知乎专栏:DesignCoder

正文从这开始~

“我总是 get 不到怎么去编程。看着一个空白的文档的时候我的头脑一片空白,千言万语不知从何写起,到底那些程序员们是如何凭空写出那么多密密麻麻的代码的?好气,我咋就做不到呢?”

尝试过学编程的朋友们肯定都有过这个感受,尽管你是选了一个号称对人类最友好的计算机语言,教程里面的每一个练习都跟着做好,当你面对一个空白的文档的时候也会面临这种不知从何下手的境况。

难道编程就真的那么难,一般人就不可能学会吗?

并不是的,今天就来给大家讲解下程序员到底是如何凭空写出一堆堆密密麻麻的代码的,程序员是怎么思考的。

其实你也可以的

想要学习编程的人的人可能都听说过廖雪峰的博客、Code Academy 之类的学习网站,在上面学习一些基本语法,做过他们的练习。

一般在这个时候都不会出现什么问题,只要认认真真地将教程看过去,练习什么的你都能够很顺畅地做出来。不要质疑因为这是练习所以才非常简单,不积跬步无以至千里,这些东西都是非常重要的基础,其实你也可以学会编程。

一切看起来都非常顺利,但是一旦要你面对一个空白的文档,写出一点东西来,你有会发现自己无从下手,千言万语不知从何说起,这时候你对自己的智商产生了深深的怀疑,自己怎么就是学不会编程呢?

不是的,你真的已经学会了,但是很多教程或者课本都没有给你足够的心理辅导。就叫这种现象做代码障碍吧。你不知从何写起,因为你没有将问题进行细化分解,细致程度无法转化成编程语言,你还怕错写出来了一堆程序却跑不动,害怕面对连你都不知道是为什么而发生的错误。

代码障碍与智商没有关系,克服代码障碍,写出代码,首先要做的是这四步:

  1. 将所有的问题转化成更小的问题。

  2. 找到解决这些小问题的办法。

  3. 将这些个解决办法合理地组装到一起。

  4. 改善、改进。

还是有点抽象。每个步骤举个实例,一看就懂了。

第一步:将所有的问题转化成更小的问题

听过赵本山的小品吧?

问:怎么将一头大象放进冰箱里面?

答:

  1. 打开冰箱。

  2. 把大象装进去。

  3. 把门盖上。

这不就装进去了吗?

当然了,这是一个段子,但这其实也是让你举步不前的最大原因。说起来好像是这么个道理,打开来,放进去,关上门,但要真那么做,其实是这件事是办不到的,因为步骤并没有那么简单。

虽然是个段子,但是请抛开段子属性,将大象装进冰箱里面完全是有可能的。我们来逻辑地去思考这些问题,你就会发现其实上面给出的答案并没完全将问题解答出来。

  1. 我们说的是啥冰箱?是家用的那种吗?还是大型冻库?

  2. 我们讲的是啥大象,大象宝宝?还是?

  3. 如果大象太大了,你要怎么做才能真的把大象摆进去呢?

  4. 你上哪去找大象啊?

  5. 你又要怎么将大象运回来?

事无巨细,特别较真,跟现实生活中你行事的方式大不一样,编程就是要这样,将所有问题细化分解成不能再分解的最小问题,然后再去逐个解决,无论是什么等级的程序员,都是这么个思路。

第二步:找到解决这些小问题的办法

第二部就是去找解决这些小小问题的办法啦。阐述的解决办法越是细致越好。

  1. 啥冰箱?——就是你厨房里面那个冰箱。

  2. 啥大象?——非洲象,不是泰国象,也不是象宝宝,就是成年非洲象。

  3. 如果大象太大了,你要怎么做才能真的把大象摆进去呢?——找把缩小枪缩小一下。

  4. 你上哪去找大象啊?——既然是非洲象,那当然是去非洲找啊。

  5. 你又要怎么将大象运回来?

通常情况下,寻找解决一个问题的办法的本身又会产生一些新的问题,上述的解决办法 3 和解决办法 4 就产生了新的问题:

  1. 上哪去找缩小枪啊?——找哆啦A梦要一把!

  2. 要去非洲的哪里找成年非洲象呢?——南非??的阿多大象公园。

第三步:将这些个解决办法合理地组装到一起

解决办法已经有了,那么接下来就是看怎么将解决办法合理地组装到一起然后执行了:

  1. 先找哆啦A梦要了一把缩小枪。

  2. 搭飞机去南非共和国。

  3. 乘车去到阿多大象公园。

  4. 在公园里面找到一头大象。

  5. 用缩小枪把大象缩小。

  6. 把缩小了的大象装到你的包包里面。

  7. 返回机场。

  8. 飞回你的国家。

  9. 乘车回到你的家里。

  10. 把大象放到你的冰箱里面去。

问题解决!NAILED IT!

上面这个只是个例子,但是里面的思路并不是在开玩笑。

咱们来个真例子

假如说你想做一个菜单按钮,当你点击按钮的时候,菜单从屏幕侧边滑出来。

(这里我们将会用 HTML+CSS+JS 来进行编写。)

第一步:将大问题细化、分解

就跟把大象装进冰箱里面的问题的思路一样,我们先将这个大问题大致地分解细化下:

  1. 这枚按钮的 HTML 要怎么写?

  2. 这枚按钮长什么样子?

  3. 点击一次,会发生什么事情?

  4. 点完之后再点一次,会发生什么事情?

  5. 再点多一次呢?

  6. 侧边出来的菜单是的 HTML 要怎么写?

  7. 侧边菜单出来的时候怎么样的?

  8. 侧边菜单在没有出来的时候又是怎么样的?

  9. 侧边菜单是怎么出来的?

  10. 它又是怎么消失的?

  11. 第一次加载页面的时候菜单要出来吗?

第二步:解决这些小问题

注意:无论是使用何种编程语言,首先你都要对这种语言以及它运行的环境有一定的了解。这里我使用的是 HTML+CSS+JS 对这个例子进行编写。

前面我们已经把将问题大致细化成了 11 个小问题,并不能保证只要你细化问题就马上知道怎么写了,但起码会有一点的头绪,知道要从何做起。并且,假如真的还是不会的话,这些个小问题扔 Google 搜一下马上也该出答案了。

接下来我们还是延续上述思路开始解答问题,开始编写程序。

  1. 这枚按钮的 HTML 要怎么写?那既然是一颗按钮,标签就用 <a>,它的类名就定作 btn 吧。

  2. 这枚按钮长什么样子?长什么样子这件事情当然是交给 CSS 处理了。

.btn {  display: inline-block;  font-size: 2em;  padding: 0.75em 1em;  background-color: #1ce;  color: #fff;  text-transform: uppercase;  text-decoration: none;}

3.4.5.点击按钮一次两次三次,会发生什么事情?

按照惯用的设计,点击一次肯定就是展示菜单啦,再点击一次就是收起,第三次点击就再展示,非常简单。这个交互行为要用到 JS 了,代码的话等我们把表现层的东西构建好再说。

1. 侧边出来的菜单是的 HTML 要怎么写?

既然是个菜单,那么就把一个表单标签放到一个 div 里面去好了,这个 div 类名就定做 sidebar。

<div class="sidebar">  <ul>    <li><a href="#">Link 1</a></li>    <li><a href="#">Link 2</a></li>    <li><a href="#">Link 3</a></li>    <li><a href="#">Link 4</a></li>    <li><a href="#">Link 5</a></li>  </ul></div>

2. 侧边菜单出来的时候怎么样的?

这个侧边菜单栏宽度是 300px,当他处于展开状态的时候会固定在屏幕最右边。其他样式上的小细节请看下面的 CSS。

.sidebar {  position: fixed;  top: 0;  bottom: 0;  right: 0;  width: 300px;  background-color: #333;}.sidebar ul {  margin: 0;  padding: 0;}.sidebar li {  list-style: none;}.sidebar li + li {  border-top: 1px solid white;}.sidebar a {  display: block;  padding: 1em 1.5em;  color: #fff;  text-decoration: none;}

3. 侧边菜单在没有出来的时候又是怎么样的?

既然侧边菜单的宽度被我们定为 300px,那么想要隐藏它的做法肯定就是让它向右边再位移 300px 移动至屏幕以外的区域啦。

这个问题的解答会产生两个新的问题:

  1. 你怎么以代码的方式来界定侧边菜单展开以及收起的状态?

  2. 收起菜单的 CSS 要怎么写?

第一小题: 我们再增加一个新类 .is-hidden ,当这个类出现的时候,菜单就会收起。

第二小题: x轴方向从左向右位移 300px,恰恰好可以将整个菜单移出屏幕。

.sidebar.is-hidden {  transform: translateX(300px);}

1. 侧边菜单是怎么出来的? 侧边菜单从屏幕最右边滑出来,所以我们还得给 sidebar 类添加一个简单的 CSS 动画。

假如你还没学会用 CSS 写动画的话,立即去 Google 一波,了解一下大概就懂了,没那么难。

.sidebar {  /* 全部其他参数 */  transition: transform 0.3s ease-out;}

2. 它又是怎么消失的?

这个问题的解答不需要写新的代码了,上面几题已经将该有的代码都写好了,让它向右边移动 300px 就好了。

3. 第一次加载页面的时候菜单要出来吗? 不用,这个菜单默认是隐藏的,所以侧边菜单栏的默认类是 sidebar is-hidden。

<div class="sidebar is-hidden">  <ul>    <li><a href="#">Link 1</a></li>    <li><a href="#">Link 2</a></li>    <li><a href="#">Link 3</a></li>    <li><a href="#">Link 4</a></li>    <li><a href="#">Link 5</a></li>  </ul></div>

好了!所有表现层的问题都已经被逐个解决掉了,我们最后来具体解决点击按钮一次两次三次,会发生什么事情?这个问题。

其实这些个操作会发生什么我们心里已经有数了。点一次就出现,但怎么写好呢?再点一次就收起,但怎么写好呢?

下边开始写 JS 来控制整个交互,虽然很简单,我会把整个解决的思路都写下来。

怎么让电脑知道你点了这枚按钮?

如果你系统地学过了 JS,那么肯定就会只要添加 click 事件的监听了。如果不懂,由于问题的细化,Google 一下也非常方便。

先在 HTML 里面找到按钮,再来给个监听。

const button = document.querySelector('.btn')button.addEventListener('click', function() {  console.log('button is clicked!')})

点击一次会发生什么

点一次会展开侧边菜单,侧边菜单滑入屏幕,那么我们就把 is-hidden 类去掉就可以了,用 JS 来去掉某个类,我们马上想到了 Element.classList.remove 来去掉 is-hidden。这同时也意味着我们要在 HTML 里面找到侧边菜单。

const button = document.querySelector('.btn')const sidebar = document.querySelector('.sidebar')button.addEventListener('click', function() {  sidebar.classList.remove('is-hidden')})

点击两次会发生什么

再点击一次当然就是收起菜单了,展开是去掉 is-hidden 类,那么收起肯定就是添加上 is-hidden 类啦。

这里我们还要让 JS 分清当要做的是展开还是收起。比较可靠简洁的做法就是在点击的时候就进行一轮判断。

const button = document.querySelector('.btn')const sidebar = document.querySelector('.sidebar')button.addEventListener('click', function() {  if (sidebar.classList.contains('is-hidden')) {    sidebar.classList.remove('is-hidden')  } else {    sidebar.classList.add('is-hidden')  }})

第四步:改善、改进

这里跳过了第三步:将这些个解决办法合理地组装到一起,直接来到了第四步,因为前面我们已经把组装的工作给做了。

最后一步是改善与改进,改善跟改进代码是需要一点经验才办得到的事情,不然你连哪里可以改进都看不出来。

所以我建议,新手们想学会细化问题的编程思路,日后积累了更多编程经验的时候再回头看看以往自己写的代码有没有可以提高的地方。

就比如说上面那个例子,假如你知道 JS 里面还有 toggle 这个方法的话,代码可以更加简短,而且不用判断。toggle 会自己判断 class 里面有没有 is-hidden,有就去掉,没有就加上。非常合乎我们想要的交互逻辑。

const button = document.querySelector('.btn')const sidebar = document.querySelector('.sidebar')button.addEventListener('click', function() {  sidebar.classList.toggle('is-hidden')})

总结

程序员们就是利用这种思路,将大问题细化成小问题然后逐个解决,最后凭空写出了一行行代码,实现了想要实现的功能。

在一边细化问题与解决问题的过程中可能会产生很多新的小问题,不要惊慌,这不是你的错,这些都是编程的一部分,将他们一并都解决了就好。

当你将每个小问题都解决好,最大的问题,也就是你的最终目标也就解决好了。

最后,你达成了你的目标,将最后的问题解决了的时候,也不要认为这就是唯一的答案,代码就像设计一样,永远都有提高的空间,学习代码也永远都有进步的余地。

关于本文译者:@PeterZ译文:https://zhuanlan.zhihu.com/p/29954974作者:@ZellLiew原文: https://medium.freecodecamp.org/how-to-think-like-a-programmer-3ae955d414cd

最后,为你推荐

【第1204期】Julie Zhuo谈如何思考职业发展

【第1229期】程序员如何在技术浪潮的更迭中保持较高的成长速度 ?

昨天早上看到的一个以程序语言为主体的咖啡,来喝杯javascript咖啡冷静下。