<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ James Z. Zhang - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ James Z. Zhang - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 25 Jun 2026 09:39:00 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/author/james/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ JavaScript Promises 工作原理——初学者手册 ]]>
                </title>
                <description>
                    <![CDATA[ 许多操作，如网络请求，本质上是异步的。在处理异步代码时，Promise 是最有用和最强大的工具之一。在这本手册中，您将了解有关 JavaScript Promises 的所有信息以及如何使用它们。 目录  1.  Promise 是什么  2.  Promise 与其他异步模式的比较  3.  如何创建一个 Promise  4.  如何获取 Promise 的结果  5.  如何使用then处理错误  6.  Promise 链  7.  如何创建立即兑现或拒绝的 Promises  8.  如何使用async和await  9.  反模式 Promise ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/the-javascript-promises-handbook/</link>
                <guid isPermaLink="false">667bd663e2419d0432abffba</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ James Z. Zhang ]]>
                </dc:creator>
                <pubDate>Wed, 26 Jun 2024 09:16:58 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/06/How-JavaScript-Promises-Work-Cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/the-javascript-promises-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How JavaScript Promises Work – Handbook for Beginners</a>
      </p><!--kg-card-begin: markdown--><p>许多操作，如网络请求，本质上是异步的。在处理异步代码时，Promise 是最有用和最强大的工具之一。在这本手册中，您将了解有关 JavaScript Promises 的所有信息以及如何使用它们。</p>
<h2 id="">目录</h2>
<ol>
<li><a href="#what-is-promise">Promise 是什么</a></li>
<li><a href="#comparison-between-promise-and-other-patterns">Promise 与其他异步模式的比较</a></li>
<li><a href="#how-to-create-a-promise">如何创建一个 Promise</a></li>
<li><a href="#get-the-result">如何获取 Promise 的结果</a></li>
<li><a href="#use-then-to-handle-errors">如何使用<code>then</code>处理错误</a></li>
<li><a href="#promise-chain">Promise 链</a></li>
<li><a href="#immediately-resolve-or-reject">如何创建立即兑现或拒绝的 Promises</a></li>
<li><a href="#use-async-and-await">如何使用<code>async</code>和<code>await</code></a></li>
<li><a href="#anti-pattern">反模式 Promise</a></li>
<li><a href="#conclusion">总结</a></li>
</ol>
<h2 id="what-is-promise"> Promise 是什么</h2>
<p>首先，让我们了解一下什么是 Promise。</p>
<p>简单来说，Promise 是一个代表异步操作的对象。这个对象可以告诉你操作何时成功，或者何时失败。</p>
<p>当你调用一个基于 Promise 的 API 时，函数返回一个 Promise 对象来告诉你最终的操作结果。</p>
<h3 id="promise">Promise 的状态</h3>
<p>在其生命周期中，Promise 可以处于以下三种状态之一：</p>
<ul>
<li><strong>待定（Pending）</strong>: 当操作仍在进行中时，Promise 处于待定状态。它处于闲置状态，等待最终结果或错误。</li>
<li><strong>已兑现（Fulfilled）</strong>：返回 Promise 的异步任务成功完成。Promise 已经被一个值兑现，该值是操作的结果。</li>
<li><strong>已拒绝（Rejected）</strong>: 如果异步操作失败，Promise 被认为是拒绝的。Promise 会有一个 <em>拒绝理由</em>。这通常是一个错误（Error）对象，也可以是任何错误值——可以是一个简单的数字或字符串！</li>
</ul>
<p>Promise 一开始处于待定（pending）状态，然后根据结果，会转换到已兑现（fulfilled）或已拒绝（rejected）状态。一旦 Promise 达到已兑现或已拒绝状态，就被认为是 <em>已敲定（settled）</em>。</p>
<p>不是所有的异步任务都会最终完成。一个 <code>Promise</code> 可能由于异步任务的代码中存在错误而永远保持在待定状态。</p>
<h2 id="comparison-between-promise-and-other-patterns">Promise 与其他异步模式的比较</h2>
<p>Promise 的工作方式与 JavaScript 的其他异步模式有点不同。在深入学习 Promise 之前，我们来简要比较一下。</p>
<h3 id="">回调函数</h3>
<p>回调函数是你传递给另一个函数的函数。当你调用的函数完成其工作后，它将用结果执行你的回调函数。</p>
<p>想象一下，一个名为 <code>getUsers</code> 的函数将发起网络请求以获取用户数组。你可以将一个回调函数传递给 <code>getUsers</code>，一旦网络请求完成，这个回调函数就会被调用，并传入用户数组：</p>
<pre><code class="language-javascript">console.log('Preparing to get users');
getUsers(users =&gt; {
  console.log('Got users:', users);
});
console.log('Users request sent');
</code></pre>
<p>一个回调函数的例子</p>
<p>首先，上述代码会打印（在 console 中显示）“Preparing to get users（准备获取用户）”。然后它调用 <code>getUsers</code>来启动网络请求。但是 JavaScript 不会等待请求完成。而是会立即执行下一个 console.log 语句（Users request sent）。</p>
<p>稍后，一旦用户被加载成功，你的回调函数将被执行，屏幕上将会显示“已获取用户”。</p>
<p>一些基于回调的 API，如许多 Node.js API，使用 <em>错误优先的回调（error-first callbacks）</em>。这些回调函数有两个参数。第一个参数是错误（error），第二个是结果（result）。</p>
<p>通常来说，取决于操作的结果，这两者中只有一个会有值。这与 Promise 的已兑现和已拒绝状态类似。</p>
<p>回调 API 的问题在于嵌套。如果你需要按顺序进行多个异步调用，你最终需要不断嵌套函数和回调函数。</p>
<p>例如，如果你想异步进行 3 个任务：读取一个文件，处理该文件中的一些数据，然后写一个新文件。</p>
<pre><code class="language-javascript">readFile('sourceData.json', data =&gt; {
	processData(data, result =&gt; {
		writeFile(result, 'processedData.json', () =&gt; {
			console.log('Done processing');
		});
	});
});
</code></pre>
<p>嵌套回调序列</p>
<p>在错误处理方面，甚至会更加笨拙。假如这些函数使用错误优先的回调：</p>
<pre><code class="language-javascript">readFile('sourceData.json', (error, data) =&gt; {
	if (error) {
		console.error('Error reading file:', error);
		return;
	}
	
	processData(data, (error, result) =&gt; {
		if (error) {
			console.error('Error processing data:', error);
			return;
		}
		
		writeFile(result, 'processedData.json', error =&gt; {
			if (error) {
				console.error('Error writing file:', error);
				return;
			}
			
			console.log('Done processing');
		});
	});
});
</code></pre>
<p>嵌套的错误优先回调序列</p>
<p>现代 API 中的异步机制通常不直接使用回调函数，但它们是其他类型异步工具（如 Promise）的基础。</p>
<h3 id="events">事件（Events）</h3>
<p>事件是你可以监听并做出响应的东西。在 JavaScript 中，一些对象是事件的 <em>发射器（emitters）</em>，这意味着你可以在这些对象上注册事件监听器（译者注：event listener，用来监视软件的变化，比如用户点击了鼠标）。</p>
<p>在 DOM 中，许多元素实现了 <code>EventTarget</code> 接口，它提供了 <code>addEventListener</code> 和 <code>removeEventListener</code> 方法。</p>
<p>一个给定类型的事件可以发生多次。例如，你可以监听按钮上的点击事件（click event）：</p>
<pre><code class="language-javascript">myButton.addEventListener('click', () =&gt; {
   console.log('button was clicked!'); 
});
</code></pre>
<p>监听按钮的点击</p>
<p>每次按钮被点击时，控制台都会打印“button was clicked!”（按钮被点击了！）。</p>
<p><code>addEventListener</code> 本身接受一个回调函数。每当事件发生时，回调函数就会被执行。</p>
<p>一个对象可以发出多种类型的事件。考虑一个图像对象。如果指定 URL 的图像成功加载，<code>加载事件（load）</code> 将被触发。如果发生错误，<code>错误事件（error）</code>将被触发。</p>
<pre><code class="language-javascript">myImage.addEventListener('load', () =&gt; {
    console.log('Image was loaded');
});

myImage.addEventListener('error', error =&gt; {
   console.error('Image failed to load:', error); 
});
</code></pre>
<p>监听图像的加载和错误事件</p>
<p>假设在你添加事件监听器之前，图像已经完成了加载。那就什么也不会发生！基于事件的 API 的一个缺点是，如果你在事件发生后添加事件监听器，你的回调将不会被执行。这是有道理的——毕竟，当你向按钮添加点击监听器时，你不会想接收所有过去的点击事件。</p>
<p>现在我们已经探讨了回调和事件，让我们看看 Promise。</p>
<h2 id="how-to-create-a-promise">如何创建 Promiose</h2>
<p>你可以使用 <code>new</code> 关键字和 <code>Promise</code> 构造器来创建一个 <code>Promise</code>。<code>Promise</code> 构造器接受一个回调函数，该函数带有两个参数，称为 <code>resolve</code> 和 <code>reject</code>。这两个参数都是由 <code>Promise</code> 提供的函数，用于将 <code>Promise</code> 转换到已兑现或已拒绝状态。</p>
<p>在你的回调中，执行你的异步工作。如果任务成功，你应该调用 <code>resolve</code> 函数并传递成功的结果。如果发生错误，则应该调用 <code>reject</code> 函数，并传递错误。</p>
<p>以下是一个创建 Promise 的示例，该示例包装了浏览器的 <code>setTimeout</code> 函数：</p>
<pre><code class="language-javascript">function wait(duration) {
	return new Promise(resolve =&gt; {
        setTimeout(resolve, duration);
    });
}
</code></pre>
<p>将 <code>setTimeout</code> 包装在 Promise 中</p>
<p><code>resolve</code> 函数作为第一个参数传递给 <code>setTimeout</code>。在由 <code>duration</code> 指定的时间过后，浏览器会调用 <code>resolve</code> 函数来兑现 Promise。</p>
<p>注意：在这个示例中，调用 <code>resolve</code> 函数之前的延迟可能比 duration 指定的时间要长。这是因为 <code>setTimeout</code> 并不能保证在指定时间内执行。</p>
<p>注意，在通常情况下，你只需要处理其他 API 返回的 Promise。而不需要手动构建自己的 Promise。</p>
<h2 id="get-the-result">如何获取 Promise 的结果</h2>
<p>我们已经看到了如何创建一个 Promise，但你如何实际获取异步操作的结果呢？为此，你需要在 Promise 对象本身上调用 <code>then</code>。<code>then</code> 接受一个回调函数作为其参数。当 Promise 被兑现时，会执行回调函数，并传入结果。</p>
<p>让我们看一个这样的例子。一个名为 <code>getUsers</code> 的函数，它异步加载用户对象列表并返回一个 Promise。你可以通过在 <code>getUsers</code> 返回的 Promise 上调用 <code>then</code> 来获取用户列表。</p>
<pre><code class="language-javascript">getUsers()
  .then(users =&gt; {
    console.log('Got users:', users);
  });
</code></pre>
<p>在 Promise 上调用 <code>then</code></p>
<p>就像处理事件或基于回调的 API 一样，你的代码将继续执行而不是等待结果。稍后，当用户数据加载完毕时，你的回调函数将被安排执行。</p>
<pre><code class="language-javascript">console.log('Loading users');
getUsers()
  .then(users =&gt; {
    console.log('Got users:', users);
  });
console.log('Continuing on');
</code></pre>
<p>在上面的例子中，首先会打印“Loading users（正在加载用户）”。因为 <code>getUsers</code> 调用仍在加载用户，所以接下来打印的将是“Continuing on（继续进行）”。稍后，你将看到打印出“Got users:（已获取用户）”。</p>
<h2 id="use-then-to-handle-errors">如何使用 `then` 处理错误</h2>
<p>我们已经看到了如何使用 <code>then</code> 来获取 Promise 提供的结果，但如果我们加载用户列表失败会发生什么？</p>
<p><code>then</code> 函数还有第二个参数，另一个回调。那就是错误处理器（error handler）。如果 Promise 被拒绝，这个回调将会用拒绝/错误值执行。</p>
<pre><code class="language-javascript">getUsers()
  .then(users =&gt; {
    console.log('Got users:', users);
  }, error =&gt; {
    console.error('Failed to load users:', error);  
  });
</code></pre>
<p>由于一个 Promise 只能被兑现（fulfilled）或被拒绝（rejected），而不能同时是两者，所以只有其中一个回调函数会被执行。</p>
<p>使用 Promise 时，务必处理错误，这一点很重要。如果你有一个 Promise 拒绝的情况没有通过错误回调处理，你的控制台会出现一个未处理拒绝的异常，这会在运行时对用户造成问题。</p>
<h2 id="promise-chain">Promise 链</h2>
<p>如果你需要连续处理多个 Promise 怎么办？我们从一个文件加载了一些数据，进行了一些处理，然后将结果写入一个新文件。假设 <code>readFile</code>，<code>processData</code> 和 <code>writeFile</code> 函数使用 Promise 而不是回调。</p>
<p>像这样：</p>
<pre><code class="language-javascript">readFile('sourceData.json')
  .then(data =&gt; {
    processData(data)
      .then(result =&gt; {
        writeFile(result, 'processedData.json')
          .then(() =&gt; {
            console.log('Done processing');
          });
      });
  });
</code></pre>
<p>嵌套的 Promise</p>
<p>这看起来并不理想，我们仍然面临着我们在回调方法中遇到的嵌套问题。幸运的是，有一个更好的方法。你可以将 promise 以平面序列方式链接起来。</p>
<p>让我们更深入地看看 <code>then</code> 是如何工作的。关键思想是：用 <code>then</code> 方法返回 <em>另一个 promise</em>。你从 <code>then</code> 回调中返回的任何值都会成为这个新 promise 的兑现值。</p>
<p>想一下，有一个 <code>getUsers</code> 函数，它返回一个 Promise，当该 Promise 被兑现时，会得到一个包含用户对象的数组。假设我们在这个 Promise 上调用 <code>then</code>，并在回调中返回数组中的第一个用户（<code>users[0]</code>）：</p>
<pre><code class="language-javascript">getUsers().then(users =&gt; users[0]);
</code></pre>
<p>这个整个表达式会产生一个新的 Promise ，将会用第一个用户对象兑现 Promise！</p>
<pre><code class="language-javascript">getUsers()
  .then(users =&gt; users[0])
  .then(firstUser =&gt; {
    console.log('First user:', firstUser.username);
  });
</code></pre>
<p>从 <code>then</code> 返回一个值</p>
<p>这种返回一个 Promise，调用 <code>then</code> 并返回另一个值，从而产生另一个 Promise 的过程，称为链式调用。</p>
<p>让我们延伸这个想法。如果我们不从 <code>then</code> 处理程序返回一个值，而是返回另一个 Promise 会怎样？再次考虑文件处理的例子，其中 <code>readFile</code> 和 <code>processData</code> 都是返回 Promise 的异步函数：</p>
<pre><code class="language-javascript">readFile('sourceData.json')
  .then(data =&gt; processData(data));
</code></pre>
<p>从 <code>then</code> 返回另一个 Promise</p>
<p><code>then</code> 处理程序调用 <code>processData</code>，并返回生成的 Promise。和之前一样，这会返回一个新的 Promise。在这种情况下，当 <code>processData</code> 返回的 Promise 被兑现时，新的 Promise 也会被兑现，并赋予相同的值。因此，上述示例中的代码将返回一个包含处理后的数据的 Promise。</p>
<p>你可以一个接一个地链式调用多个 Promises，直到你得到所需的最终值：</p>
<pre><code class="language-javascript">readFile('sourceData.json')
  .then(data =&gt; processData(data))
  .then(result =&gt; writeFile(result, 'processedData.json'))
  .then(() =&gt; console.log('Done processing'));
</code></pre>
<p>链式调用多个 Promises</p>
<p>在上述示例中，整个表达式将返回一个 Promise，该 Promise 在处理后的数据写入文件后才会被兑现。控制台打印“Done processing!（处理完成）”，然后最终的 Promise 才会被兑现。</p>
<h3 id="promise">链式调用 Promise 的错误处理</h3>
<p>在我们的文件处理示例中，过程中的任何阶段都可能发生错误。你可以使用 Promise 的 <code>catch</code> 方法来处理任何步骤中的错误。</p>
<pre><code class="language-javascript">readFile('sourceData.json')
  .then(data =&gt; processData(data))
  .then(result =&gt; writeFile(result, 'processedData.json'))
  .then(() =&gt; console.log('Done processing'))
  .catch(error =&gt; console.log('Error while processing:', error));
</code></pre>
<p>使用 <code>catch</code> 来处理错误</p>
<p>如果链式调用中的某个 Promise 被拒绝，传递给 <code>catch</code> 的回调函数将会执行，并跳过整个链式调用中的剩余部分。</p>
<h3 id="finally">如何使用 <code>finally</code></h3>
<p>如果你希望无论 Promise 的结果如何都要执行一些操作。例如，关闭一个数据库或文件。可以使用 finally 方法。</p>
<pre><code class="language-javascript">openDatabase()
  .then(data =&gt; processData(data))
  .catch(error =&gt; console.error('Error'))
  .finally(() =&gt; closeDatabase());
</code></pre>
<h3 id="promiseall">如何使用 <code>Promise.all</code></h3>
<p>Promise 链式调用可以让你按顺序运行多个任务，但如果你想同时运行多个任务，<code>Promise.all</code> 方法可以让你做到这一点。</p>
<p><code>Promise.all</code> 接受一个 Promise 数组，并返回一个新的 Promise。当所有其他 Promise 都被兑现时，这个新的 Promise 也将被兑现。其兑现值是一个数组，包含了输入数组中每个 Promise 的兑现值。</p>
<p>假设你有一个函数 <code>loadUserProfile</code> 用于加载用户的个人资料数据，另一个函数 <code>loadUserPosts</code> 用于加载用户的帖子。它们都以用户 ID 作为参数。还有第三个函数 <code>renderUserPage</code> 需要同时获取用户的个人资料和帖子列表。</p>
<pre><code class="language-javascript">const userId = 100;

const profilePromise = loadUserProfile(userId);
const postsPromise = loadUserPosts(userId);

Promise.all([profilePromise, postsPromise])
  .then(results =&gt; {
    const [profile, posts] = results;
    renderUserPage(profile, posts);
  });
</code></pre>
<p>使用 <code>Promise.all</code> 等待多个 Promise</p>
<p>如果出现错误怎么办呢？如果传递给 <code>Promise.all</code> 的任何一个 Promise 因错误而被拒绝，生成的 Promise 也将被该错误拒绝。其他任何被兑现的 Promise 的值都将会丢失。</p>
<h3 id="promiseallsettled">如何使用 <code>Promise.allSettled</code></h3>
<p><code>Promise.allSettled</code> 方法的工作方式类似于 <code>Promise.all</code>。主要区别在于 <code>Promise.allSettled</code> 返回的 Promise 永远不会被拒绝。</p>
<p>相反，它会以一个对象数组来兑现，这些对象的顺序对应于输入数组中的 Promise 的顺序。每个对象都有一个 <code>status</code> 属性，该属性根据结果分别为 "fulfilled（已兑现）" 或 "rejected（已拒绝）"。</p>
<p>如果 <code>status</code> 是 "fulfilled（已兑现）"，该对象还会有一个 <code>value</code> 属性，表示 Promise 的兑现值。如果 <code>status</code> 是 "rejected"，对象将有一个 <code>reason</code> 属性，用来表示 Promise 被拒绝时的错误或其他对象。</p>
<p>再看一个 <code>getUser</code> 函数，该函数接受一个用户 ID 并返回一个 Promise，该 Promise 将会被具有该 ID 的用户实现。你可以使用 <code>Promise.allSettled</code> 并行加载这些用户，确保获取所有成功加载的用户。</p>
<pre><code class="language-javascript">Promise.allSettled([
  getUser(1),
  getUser(2),
  getUser(3)
]).then(results =&gt; {
   const users = results
     .filter(result =&gt; result.status === 'fulfilled')
     .map(result =&gt; result.value);
   console.log('Got users:', users);
});
</code></pre>
<p>尝试加载三个用户，并显示成功加载的用户</p>
<p>你可以创建一个通用的 <code>loadUsers</code> 函数，该函数接收一个用户 ID 数组，并且并行加载用户。该函数返回一个 Promise，当所有用户成功加载时，该 Promise 将被兑现，并包含一个用户数组。</p>
<pre><code class="language-javascript">function getUsers(userIds) {
  return Promise.allSettled(userIds.map(id =&gt; getUser(id)))
    .then(results =&gt; {
      return results
        .filter(result =&gt; result.status === 'fulfilled')
        .map(result =&gt; result.value);
    });
}
</code></pre>
<p>一个辅助函数，用于并行加载多个用户，过滤掉任何失败的请求。</p>
<p>然后，你只需使用一个用户 ID 数组调用 <code>getUsers</code>：</p>
<pre><code class="language-javascript">getUsers([1, 2, 3])
	.then(users =&gt; console.log('Got users:', users));
</code></pre>
<p>使用 <code>getUsers</code> 辅助函数</p>
<h2 id="immediately-resolve-or-reject">如何创建立即兑现或拒绝的 Promise</h2>
<p>你希望将一个值包装在一个已兑现的 Promise 中。例如，你有一个返回 Promise 的异步函数，并且你提前知道值，不需要进行任何异步工作。</p>
<p>可以调用 <code>Promise.resolve</code> 并且指定一个值，这会返回一个立即兑现的 Promise，并带有你指定的值：</p>
<pre><code class="language-javascript">Promise.resolve('hello')
  .then(result =&gt; {
    console.log(result); // prints "hello"
  });
</code></pre>
<p>使用 <code>Promise.resolve</code></p>
<p>这等同于：</p>
<pre><code class="language-javascript">new Promise(resolve =&gt; {
   resolve('hello'); 
}).then(result =&gt; {
    console.log(result); // also prints "hello"
});
</code></pre>
<p>你可以创建一个立即兑现的 Promise 并在这种情况下返回来使你的 API 更加一致。这样，调用你函数的代码就知道无论如何总是会得到一个 Promise。</p>
<p>例如，考虑之前定义的 <code>getUsers</code> 函数。如果用户 ID 数组为空，你可以简单地返回一个空数组，因为不会加载任何用户。</p>
<pre><code class="language-javascript">function getUsers(userIds) {
  // immediately return the empty array
  if (userIds.length === 0) {
    return Promise.resolve([]);
  }
    
  return Promise.allSettled(userIds.map(id =&gt; getUser(id)))
    .then(results =&gt; {
      return results
        .filter(result =&gt; result.status === 'fulfilled')
        .map(result =&gt; result.value);
    });
}
</code></pre>
<p>在 <code>getUsers</code> 辅助函数中添加一个提前返回的功能</p>
<p><code>Promise.resolve</code> 的另一个用途是处理你可能获得一个值，该值可能是也可能不是一个 Promise，但你想总是将它视为一个 Promise。</p>
<p>你可以安全地对任何值调用 <code>Promise.resolve</code>。如果它已经是一个 Promise，你将得到另一个具有相同兑现值或拒绝值的 Promise。如果它不是一个 Promise，它将被包装在一个立即兑现的 Promise 中。</p>
<p>这种方法的好处是你不必做这样的事情：</p>
<pre><code class="language-javascript">function getResult(result) {
  if (result.then) {
     result.then(value =&gt; {
         console.log('Result:', value);
     });
  } else {
      console.log('Result:', result);
  }
}
</code></pre>
<p>根据是否是 Promise 有条件地调用 <code>then</code></p>
<p>同样，你可以使用 <code>Promise.reject</code> 创建一个立即拒绝的 Promise。再回到 <code>getUsers</code> 函数，如果用户 ID 数组是 <code>null</code>、<code>undefined</code> 或不是数组，我们希望立即拒绝。</p>
<pre><code class="language-javascript">function getUsers(userIds) {
  if (userIds == null || !Array.isArray(userIds)) {
    return Promise.reject(new Error('User IDs must be an array'));
  }
    
  // immediately return the empty array
  if (userIds.length === 0) {
    return Promise.resolve([]);
  }
    
  return Promise.allSettled(userIds.map(id =&gt; getUser(id)))
    .then(results =&gt; {
      return results
        .filter(result =&gt; result.status === 'fulfilled')
        .map(result =&gt; result.value);
    });
}
</code></pre>
<p>如果参数不是一个有效数组则返回一个错误对象</p>
<h3 id="promiserace">如何使用 <code>Promise.race</code></h3>
<p>就像 <code>Promise.all</code> 或 <code>Promise.allSettled</code> 一样，<code>Promise.race</code> 静态方法接收一个 Promise 数组，并返回一个新的 Promise。只是它的工作方式有些不同。</p>
<p><code>Promise.race</code> 返回的 Promise 会等待给定的 Promise 中第一个被兑现或被拒绝的 Promise，然后该 Promise 也会以相同的值被兑现或被拒绝。当这种情况发生时，其他 Promise 的兑现或拒绝值将会丢失。</p>
<h3 id="promiseany">如何使用 <code>Promise.any</code></h3>
<p><code>Promise.any</code> 的工作方式与 <code>Promise.race</code> 类似，但有一个关键区别 —— <code>Promise.race</code> 会在任何一个 Promise 被兑现或被拒绝时完成，而 <code>Promise.any</code> 会等待第一个被 <em>兑现的</em> Promise。</p>
<h2 id="use-async-and-await">如何使用 `async` 和 `await`</h2>
<p><code>async</code> 和 <code>await</code> 是简化处理 Promise 的特殊关键字。它们消除了对回调函数和调用 <code>then</code> 或 <code>catch</code> 的需求。它们也可以与 try-catch 模块一起使用。</p>
<p>它们的工作原理如下。你无需在 Promise 上调用 <code>then</code>，而是通过在它前面加上 <code>await</code> 关键词来“等待”它。这实际上会“暂停”函数的执行，直到 Promise 被兑现。</p>
<p>以下是一个标准 Promise 的例子：</p>
<pre><code class="language-javascript">getUsers().then(users =&gt; {
    console.log('Got users:', users);
});
</code></pre>
<p>使用 <code>then</code> 等待一个 promise</p>
<p>以下是使用 <code>await</code> 关键字的等效代码：</p>
<pre><code class="language-javascript">const users = await getUsers();
console.log('Got users:', users);
</code></pre>
<p>使用 <code>await</code> 等待一个 promise</p>
<p>Promise 连续操作也更加简洁：</p>
<pre><code class="language-javascript">const data = await readFile('sourceData.json');
const result = await processData(data);
await writeFile(result, 'processedData.json');
</code></pre>
<p>使用 <code>await</code> 链接 promise</p>
<p>记住，每次使用 <code>await</code> 都会暂停函数的其余部分的执行，直到你等待的 Promise 被兑现。如果你想等待多个并行运行的 Promise，你可以使用 <code>Promise.all</code>：</p>
<pre><code class="language-javascript">const users = await Promise.all([getUser(1), getUser(2), getUser(3)]);
</code></pre>
<p>使用 <code>await</code> 的 Promise.all</p>
<p>要使用 <code>await</code> 关键字，你的函数必须标记为异步函数。你可以在函数前面加上 <code>async</code> （异步）关键字来实现这一点：</p>
<pre><code class="language-javascript">async function processData(sourceFile, outputFile) {
  const data = await readFile(sourceFile);
  const result = await processData(data);
  writeFile(result, outputFile);
}
</code></pre>
<p>标记函数为 <code>async</code></p>
<p>添加 <code>async</code> 关键字还对函数产生了另一个重要影响。异步函数始终会隐匿地返回一个 Promise。如果你从异步函数中返回一个值，该函数实际上会返回一个以该值兑现的 Promise。</p>
<pre><code class="language-javascript">async function add(a, b) {
  return a + b;   
}

add(2, 3).then(sum =&gt; {
   console.log('Sum is:', sum); 
});
</code></pre>
<p>一个 <code>async</code> 函数用于求两个数字的和</p>
<p>在上面的例子中，该函数返回两个参数 <code>a</code> 和 <code>b</code> 的 <em>和</em>。但由于它是一个 <code>async</code> 函数，它不会直接返回 <em>和</em>，而是返回一个带有 <em>和</em> 的被兑现的 Promise 。</p>
<h3 id="asyncawait">使用 <code>async</code> 和 <code>await</code> 进行错误处理</h3>
<p>我们使用 <code>await</code> 来等待 Promise 被兑现，但是如果你等待一个 Promise，并且它被拒绝了，就会抛出一个错误。你可以将其放在一个 try-catch 模块中来处理错误：</p>
<pre><code class="language-javascript">try {
    const data = await readFile(sourceFile);
    const result = await processData(data);
    await writeFile(result, outputFile);
} catch (error) {
    console.error('Error occurred while processing:', error);
}
</code></pre>
<p>使用 try-catch 模块进行错误处理</p>
<h2 id="anti-pattern">Promise 的反模式</h2>
<h3 id="promise">不需要创建新 Promise 的情况</h3>
<p>有时候无法避免创建新的 Promise。但是，如果已经有 API 返回的 Promise 你就不需要创建自己的：</p>
<pre><code class="language-javascript">function getUsers() {
  return new Promise(resolve =&gt; {
     fetch('https://example.com/api/users')
       .then(result =&gt; result.json())
       .then(data =&gt; resolve(data))
  });
}
</code></pre>
<p>创建不必要的 Promise 的例子</p>
<p>在这个例子中，我们创建一个新的 Promise 来包装 Fetch API，而 Fetch API 已经返回 Promise。这是不必要的。我们可以直接返回 Fetch API 的 Promise 链式调用：</p>
<pre><code class="language-javascript">function getUsers() {
  return fetch('https://example.com/api/users')
    .then(result =&gt; result.json());
}
</code></pre>
<p>使用现有的 Fetch promise</p>
<p>在这两种情况下，调用 <code>getUsers</code> 的代码看起来都是一样的：</p>
<pre><code class="language-javascript">getUsers()
  .then(users =&gt; console.log('Got users:', users))
  .catch(error =&gt; console.error('Error fetching users:', error));
   
</code></pre>
<p>任一种 <code>getUsers()</code> 函数实现都可以使用这段客户端代码来调用</p>
<h3 id="">吞噬错误</h3>
<p>来看这个版本的 <code>getUsers</code> 函数：</p>
<pre><code class="language-javascript">function getUsers() {
    return fetch('https://example.com/api/users')
    	.then(result =&gt; result.json())
    	.catch(error =&gt; console.error('Error loading users:', error));
}
</code></pre>
<p>吞噬 Fetch 错误</p>
<p>错误处理很好，对吧？如果我们调用这个 <code>getUsers</code> 函数，你可能会对结果感到惊讶：</p>
<pre><code class="language-javascript">getUsers()
  .then(users =&gt; console.log('Got users:', users))
  .catch(error =&gt; console.error('error:', error);)
</code></pre>
<p>调用 <code>getUsers</code></p>
<p>你可能期望这会打印出 "error（错误）"，但实际上它会打印出 "Got users: undefined"。这是因为 <code>catch</code> 调用"吞噬"了错误，并返回一个新的 Promise，该 Promise 用 <code>catch</code> 回调的返回值 <code>undefined</code>（<code>console.error</code> 返回 <code>undefined</code>）来兑现。你仍然会看到来自 <code>getUsers</code> 的 "Error loading users" 日志消息，但返回的 Promise 将会被兑现，而不是被拒绝。</p>
<p>如果你想在 <code>getUsers</code> 函数内部捕获错误并且仍然拒绝返回的 Promise，<code>catch</code> 处理程序需要返回一个被拒绝的 Promise。你可以通过使用 <code>Promise.reject</code> 来实现这一点。</p>
<pre><code class="language-javascript">function getUsers() {
  return fetch('https://example.com/api/users')
    .then(result =&gt; result.json())
    .catch(error =&gt; {
      console.error('Error loading users:', error);
      return Promise.reject(error);
    });
}
</code></pre>
<p>在处理错误后返回一个被拒绝的 Promise</p>
<p>现在你仍然会得到 "Error loading users（加载用户错误）" 的消息，但返回的 Promise 也会因错误而被拒绝。</p>
<h3 id="promise">Promise 的嵌套</h3>
<p>避免嵌套 Promise，尝试使用扁平化的 Promise 链式调用。</p>
<p>不要这样：</p>
<pre><code class="language-javascript">readFile(sourceFile)
  .then(data =&gt; {
    processData(data)
      .then(result =&gt; {
        writeFile(result, outputFile)
          .then(() =&gt; console.log('done');
      });
  });
</code></pre>
<p>应该这样：</p>
<pre><code class="language-javascript">readFile(sourceFile)
  .then(data =&gt; processData(data))
  .then(result =&gt; writeFile(result, outputFile))
  .then(() =&gt; console.log('done'));
</code></pre>
<h2 id="conclusion">总结</h2>
<p>以下是使用 Promise 的关键要点：</p>
<ul>
<li>Promise 可以是 pending（待定）、fulfilled（已兑现）或 rejected（已拒绝）</li>
<li>如果一个 Promise 被兑现（fulfilled）或被拒绝（rejected），它就是被解决了(settled),</li>
<li>使用 <code>then</code> 来获取 Promise 的兑现值（以及进行下一步的操作）</li>
<li>使用 <code>catch</code> 来处理错误</li>
<li>使用 <code>finally</code> 来执行在成功或错误情况下都需要的清理逻辑</li>
<li>链接 Promise 以按顺序执行异步任务</li>
<li>使用 <code>Promise.all</code> 来获得一个 Promise，当所有给定的 Promise 都被兑现时它就会被兑现（fulfilled），或当其中一个 Promise 被拒绝时它被拒绝（rejected）</li>
<li>使用 <code>Promise.allSettled</code> 来获得一个 Promise，当所有给定的 Promise 都被兑现（fulfilled）或被拒绝（rejected）时它被解决</li>
<li>使用 <code>Promise.race</code> 来获得一个 Promise，当给定的 Promise 中第一个被兑现或被拒绝时它也被兑现或被拒绝</li>
<li>使用 <code>Promise.any</code> 来获得一个 Promise，当给定的 Promise 中第一个被兑现时它被兑现</li>
<li>使用 <code>await</code> 关键字来等待一个 Promise 的兑现值</li>
<li>使用 try-catch 模块来处理使用 <code>await</code> 关键字时产生的错误</li>
<li>使用 <code>await</code> 的函数必须使用 <code>async</code> 关键字</li>
</ul>
<p>感谢阅读这篇关于 Promise 的深入探讨。希望你学到了新知识！</p>
<!--kg-card-end: markdown--><p>感谢 <a href="https://www.freecodecamp.org/chinese/news/author/mingxun/">Mingxun Liu</a> 校对这篇译文。</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 如何开始学习编程——初学者手册 ]]>
                </title>
                <description>
                    <![CDATA[ 在这本手册中，我将解决你可能会问自己的一个问题：我是否应该学习编程？ 在向你解释为什么应该之后，我将介绍成为软件开发人员的一些好处和挑战。我还将讨论一些学习编程的关键策略，以帮助你取得成功。 最后，你将会对学习编程需要什么以及如何开始或继续你的旅程有一个全新的认知。 目录  * 什么是编程  * 你还应该学习编程吗-是的  * 为什么你应该考虑把编程作为职业  * 编程工作的潜在挑战  * 为什么软件工程师薪水这么高  * 如何为你的编程之旅做准备  * 你的自我意识是你的敌人  * 对你的学习负责  * 我害怕编程--我该怎么办  * 学习编程的策略和技巧  * 你能在一个晚上学会编程吗  * 避免教程地狱  * 如何通过费曼技巧理解复杂主题  * 不要记忆语法  * 保持一个待学习列表  ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/learn-coding-for-everyone-handbook/</link>
                <guid isPermaLink="false">6656b122c2672603d0493f94</guid>
                
                    <category>
                        <![CDATA[ 学习编程 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ James Z. Zhang ]]>
                </dc:creator>
                <pubDate>Wed, 29 May 2024 04:19:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2024/05/How-to-Start-Learning-to-Code-cover--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>原文：</strong> <a href="https://www.freecodecamp.org/news/learn-coding-for-everyone-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Start Learning to Code – Handbook for Beginners</a>
      </p><!--kg-card-begin: markdown--><p>在这本手册中，我将解决你可能会问自己的一个问题：我是否应该学习编程？</p>
<p>在向你解释为什么应该之后，我将介绍成为软件开发人员的一些好处和挑战。我还将讨论一些学习编程的关键策略，以帮助你取得成功。</p>
<p>最后，你将会对学习编程需要什么以及如何开始或继续你的旅程有一个全新的认知。</p>
<h1 id="">目录</h1>
<ul>
<li><a href="#%E4%BB%80%E4%B9%88%E6%98%AF%E7%BC%96%E7%A8%8B">什么是编程</a></li>
<li><a href="#%E4%BD%A0%E8%BF%98%E5%BA%94%E8%AF%A5%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B%E5%90%97-%E6%98%AF%E7%9A%84">你还应该学习编程吗-是的</a></li>
<li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E5%BA%94%E8%AF%A5%E8%80%83%E8%99%91%E6%8A%8A%E7%BC%96%E7%A8%8B%E4%BD%9C%E4%B8%BA%E8%81%8C%E4%B8%9A">为什么你应该考虑把编程作为职业</a></li>
<li><a href="#%E7%BC%96%E7%A8%8B%E5%B7%A5%E4%BD%9C%E7%9A%84%E6%BD%9C%E5%9C%A8%E6%8C%91%E6%88%98">编程工作的潜在挑战</a></li>
<li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%B8%88%E8%96%AA%E6%B0%B4%E8%BF%99%E4%B9%88%E9%AB%98">为什么软件工程师薪水这么高</a></li>
<li><a href="#%E5%A6%82%E4%BD%95%E4%B8%BA%E4%BD%A0%E7%9A%84%E7%BC%96%E7%A8%8B%E4%B9%8B%E6%97%85%E5%81%9A%E5%87%86%E5%A4%87">如何为你的编程之旅做准备</a></li>
<li><a href="#%E4%BD%A0%E7%9A%84%E8%87%AA%E6%88%91%E6%84%8F%E8%AF%86%E6%98%AF%E4%BD%A0%E7%9A%84%E6%95%8C%E4%BA%BA">你的自我意识是你的敌人</a></li>
<li><a href="#%E5%AF%B9%E4%BD%A0%E7%9A%84%E5%AD%A6%E4%B9%A0%E8%B4%9F%E8%B4%A3">对你的学习负责</a></li>
<li><a href="#%E6%88%91%E5%AE%B3%E6%80%95%E7%BC%96%E7%A8%8B--%E6%88%91%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E">我害怕编程--我该怎么办</a></li>
<li><a href="#%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B%E7%9A%84%E7%AD%96%E7%95%A5%E5%92%8C%E6%8A%80%E5%B7%A7">学习编程的策略和技巧</a></li>
<li><a href="#%E4%BD%A0%E8%83%BD%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%99%9A%E4%B8%8A%E5%AD%A6%E4%BC%9A%E7%BC%96%E7%A8%8B%E5%90%97">你能在一个晚上学会编程吗</a></li>
<li><a href="#%E9%81%BF%E5%85%8D%E6%95%99%E7%A8%8B%E5%9C%B0%E7%8B%B1">避免教程地狱</a></li>
<li><a href="#%E5%A6%82%E4%BD%95%E9%80%9A%E8%BF%87%E8%B4%B9%E6%9B%BC%E6%8A%80%E5%B7%A7%E7%90%86%E8%A7%A3%E5%A4%8D%E6%9D%82%E4%B8%BB%E9%A2%98">如何通过费曼技巧理解复杂主题</a></li>
<li><a href="#%E4%B8%8D%E8%A6%81%E8%AE%B0%E5%BF%86%E8%AF%AD%E6%B3%95">不要记忆语法</a></li>
<li><a href="#%E4%BF%9D%E6%8C%81%E4%B8%80%E4%B8%AA%E5%BE%85%E5%AD%A6%E4%B9%A0%E5%88%97%E8%A1%A8">保持一个待学习列表</a></li>
<li><a href="#%E7%BC%96%E7%A8%8B%E7%9A%84%E5%AE%9E%E9%99%85%E6%96%B9%E9%9D%A2">编程的实际方面</a></li>
<li><a href="#%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E5%9B%B0%E9%9A%BE%E7%9A%84%E9%A1%B9%E7%9B%AE">如何处理困难的项目</a></li>
<li><a href="#%E5%A6%82%E4%BD%95%E9%80%89%E6%8B%A9%E8%A6%81%E6%9E%84%E5%BB%BA%E7%9A%84%E9%A1%B9%E7%9B%AE">如何选择要构建的项目</a></li>
<li><a href="#%E9%80%9A%E8%BF%87%E4%BB%8E%E5%A4%B4%E5%BC%80%E5%A7%8B%E6%9E%84%E5%BB%BA%E6%9D%A5%E5%AD%A6%E4%B9%A0">通过从头开始构建来学习</a></li>
<li><a href="#%E6%9E%84%E5%BB%BA%E5%B7%B2%E7%BB%8F%E5%AD%98%E5%9C%A8%E7%9A%84%E4%B8%9C%E8%A5%BF">构建已经存在的东西</a></li>
<li><a href="#%E8%B6%85%E8%B6%8A%E5%9F%BA%E7%A1%80">超越基础</a></li>
<li><a href="#%E5%9F%B9%E5%85%BB%E5%AD%A6%E4%B9%A0%E7%9A%84%E7%83%AD%E7%88%B1">培养学习的热爱</a></li>
<li><a href="#%E7%9C%8B%E5%A4%A7%E5%B1%80">看大局</a></li>
<li><a href="#%E6%8B%A5%E6%8A%B1%E7%BB%88%E8%BA%AB%E5%AD%A6%E4%B9%A0">拥抱终身学习</a></li>
<li><a href="#%E8%8E%B7%E5%8F%96%E6%9C%AC%E4%B9%A6%E7%9A%84pdf%E7%89%88%E6%9C%AC">获取本书的 PDF 版本</a></li>
</ul>
<h1 id="">编程介绍</h1>
<h2 id="">什么是编程?</h2>
<p>在我们开始讲建议之前，让我们先了解一下什么是计算机编程。</p>
<p>首先，请记住，计算机不仅仅是笔记本电脑或台式机。它还包括你的手机、平板电脑以及任何能够执行我们编程到其中的逻辑和算术操作的设备。</p>
<p>包括你汽车的导航系统、你取款或存款的 ATM 机、外卖订餐系统等等。</p>
<p>计算机编程是设计和构建计算机可以执行的指令（“程序”）的过程。</p>
<p>举一个例子，我们用计算器进行加减乘除的运算。</p>
<p>我们不需要铅笔在纸上做这些运算——因为，手机上有计算器。而这个计算器是一个计算程序，给我们提供结果。</p>
<p>你每天使用的其他程序可能包括脸书/Facebook、WhatsApp、Instagram、油管/YouTube、抖音/TikTok 之类的。</p>
<p>编写程序有点像做顿饭。你可能有一个美味的菜谱（想法），但你需要先去买菜。</p>
<p>一旦你得到了所需要的食材，你准备这些食物，把它放进烤箱，然后等它烤好。之后，你把食物端上桌，开始享用。</p>
<p>编程也类似：首先，你有一个想法和将这个想法变成程序的知识（或者你在构建程序的过程中学习——就像你可以在 YouTube 上观看别人做饭并学习如何做那个菜谱一样）。</p>
<p>然后，你开始逐步地把程序的成分放到位，直到整个程序准备好可以供用户使用。</p>
<p>与烹饪不同的是，菜肴被食用后会消失，而程序在使用后仍然完好无损且可重复使用。</p>
<p>这一独特的方面意味着一个程序可以同时为多个用户服务并且可以长期使用。</p>
<p>创建和维护软件是有成本的，但一旦开发出来，像网站这样的程序可以被许多人同时访问，而不会减少其可用性或质量。</p>
<p>总而言之，编程是将一个想法转变成其他人可以使用的计算机程序的过程。而这是一项你可以自己学习的技能。</p>
<p>在不断发展的软件工程领域，许多人都在关注 AI 将带来的影响。</p>
<p>你还应该学习编程吗？（简短的答案：是的。）让我们深入探讨这个问题，特别是针对那些对未来编程技能需求持怀疑态度的人。</p>
<h2 id="">你还应该学习编程吗-是的</h2>
<p>我们一直在使用软件——与他人聊天，了解最新新闻，甚至用于帮助我们准时起床的闹钟。</p>
<p>甚至你用来阅读文档的浏览器或 PDF 阅读器也是软件。这些文字也是在一个软件程序中输入的。</p>
<p>编程是一个不断发展的领域，我们目前手动完成的许多事情将来可能会自动化。</p>
<p>但软件已经深深嵌入到我们的日常生活中，为各种职业和个人活动提供工具和应用程序。</p>
<p>我们越是融入数字世界，软件就变得越重要。它正在重塑我们的工作、学习和社交方式，其重要性只会越来越高。</p>
<h3 id="">软件开发的未来</h3>
<p>想象一个世界，构建软件就像与一个高度先进的 AI（如未来的 ChatGPT）对话一样简单。你描述你的需求，AI 为你创建整个软件——无需编程。</p>
<p>那么你可能会问：当 ChatGPT 可以在几秒钟内为我编写整个应用程序时，为什么我还要学习编程？好吧，我想让你明白一点：AI 并不是来取代我们的，而是<strong>帮助我们变得更高效</strong>。</p>
<p>当然，AI 可以通过为你执行某些基本的、重复的任务来帮助你节省时间和精力。但掌握软件开发的基础仍然很重要，特别是对于那些需要你的创造力和基于经验的复杂问题。</p>
<p>你需要能够利用 AI 的力量，同时继续学习和适应。这将帮助确保我们在快速发展的数字世界中把握方向。</p>
<p>如你所见，我想强调软件工程师和程序员在即使是 AI 主导的未来中也是不可替代的。以下是几个原因：</p>
<ol>
<li><strong>理解胜过自动化</strong>：编程不仅仅是执行任务——它是理解复杂的逻辑和结构。我们人类分析和解决复杂问题的能力超越了 AI 的自动化。</li>
<li><strong>维护性和灵活性</strong>：深度编码知识为软件维护和调整提供了重要的见解。当 AI 生成的程序遇到问题时，这种知识是必不可少的。</li>
<li><strong>安全性和可靠性</strong>：就像了解基本的汽车机械原理对于安全一样，了解编程基础对于解决软件故障是必要的。</li>
<li><strong>创造性元素</strong>：AI 缺乏人类的创造力和创新，这对于设想和实现新颖的软件解决方案至关重要。</li>
</ol>
<p>AI 在编码中的崛起并不意味着人类编码员的终结。相反，我认为这只是预示着一个协作的未来。AI 自动化日常任务为人类编码员在软件开发中提供了更多的创造和创新空间。</p>
<p>学习编程超越了单纯的编程。这是关于理解各种技术的运作方式，培养解决问题的能力和激发创造力。即使在 AI 重塑的环境中，这些技能仍然是无价的。</p>
<p>所以我鼓励你接受编程，因为它为人类智能和 AI 合作推动创新的未来打开了大门。</p>
<h2 id="">为什么你应该考虑把编程作为职业</h2>
<p>也许当你还是个孩子的时候（或者现在作为一个成年人），你非常喜欢一个电脑游戏，现在你还在玩它。</p>
<p>也许你曾经想过有一天你可以开发一个类似的游戏。</p>
<p>我认识一些人正是因为这个原因而开始编程：为了开发不同的电脑游戏。</p>
<p>由于你可能体验到乐趣，你决定自己成为一名程序员。</p>
<p>随着时间的推移，你的理由可能会改变——这当然并不意味着每个人都是因为游戏开发才开始学习编码。</p>
<p>毕竟，你有许多理由考虑将编程作为职业选择。现在，让我们来讨论其中的一些理由（实际上还有更多）。</p>
<h3 id="">你可以开发一些有趣的东西</h3>
<p>我提到了游戏开发的案例，但你不必通过构建游戏来开始编程。</p>
<p>也许你是一名会计，或者你有一家商店并想通过自己开发的程序来登记你的商品...等等。</p>
<p>这里有一些可能激发人学习编程的实际项目：</p>
<ul>
<li>一个定制的笔记应用程序，满足你特定的需求</li>
<li>一个个性化的库存管理系统，用于你的商店</li>
<li>一个用于组织和跟踪你的日常任务和目标的应用程序</li>
<li>一个用于管理你的大学或大学课程表的调度程序</li>
<li>一个解决问题的助手，用于处理具有挑战性的任务</li>
<li>一个每日天气更新工具，向你的电子邮件发送天气预报</li>
<li>一个健康应用程序，基于症状建议可能的疾病</li>
<li>一个专注力增强器，在工作时间限制访问社交媒体</li>
</ul>
<p>还有许多其他程序你可以开发。简而言之，你可以因为喜欢解决日常生活中面临的问题而开始编程。</p>
<p>一旦你学会了编程并能够构建这些程序，你可以与朋友和家人（甚至更广泛的群体）分享它们。</p>
<h3 id="">你能够为世界各地人们解决问题</h3>
<p>这里有件事情也许会让你开心：有机会帮助别人（或许多人）。我相信当你能够帮助家人或同事时，你会感到快乐和满足。</p>
<p>现在，想象一下如果你有机会解决世界各地人们面临的问题会有多好。</p>
<p>例如，你可能有一个想法，在 Facebook 上为你所在社区的居民创建一个小组，以便大家互相询问所需的家庭工具。</p>
<p>或者你想建议大家共同维护社区的公共空间。</p>
<p>你还可以在这个小组里提出问题以及你希望实现的解决方案。</p>
<p>如果你知道如何编程，你可以创建自己的工具并与邻居分享。你可以使你的平台满足你社区的特定需求。</p>
<p>如果它在你的社区中有效，你就可以与其他社区的人分享它。</p>
<p>你可以更进一步，开展帮助不同领域工作的人们的项目。</p>
<p>例如，除了帮助你所在社区的居民，你还可以通过构建一个天气报告应用程序来帮助农民更好地了解天气状况。</p>
<p>或者你可以开发一个推荐系统，帮助他们确定如何耕作土地以及何时种植什么作物。</p>
<p>或者你想帮助一个理发师在剪发前可视化客户的发型。或者你甚至可以构建程序来帮助私人医疗诊所更好地管理患者记录。</p>
<p>希望你开始看到，可能性几乎是无穷无尽的。</p>
<h3 id="">你可以迎接有趣的挑战</h3>
<p>编程的一个主要优点是你可以利用所学的知识解决各种不同的问题。</p>
<p>有时你可能会开始阅读一本书，或者看一部你不喜欢的电影，你可以选择放弃那本书或电影，开始另一部。</p>
<p>同样的情况也适用于编程项目。你可能对某个项目并不太感兴趣，你通常可以换一个项目。</p>
<p>即使在工作中，你也可以时不时地请求经理分配你到不同的项目。</p>
<h3 id="">你也可以在工作的时候学习</h3>
<p>许多公司在没有工作任务时，为程序员提供在工作时间学习的空间和机会。</p>
<p>事实上，有些公司会承担培训、书籍和各种课程的费用，以使员工获得资质和为工作做好准备。</p>
<p>在一些公司，当你完成认证后，你会得到奖励，无论是金钱还是其他各种形式的。</p>
<p>有技能、有准备并经过培训的程序员对公司来说是非常有价值的资源。除了能够处理更复杂的项目外，他们通常还有机会获得更好的客户和报价。公司也可以通过晋升这些高技能的开发人员来投资他们。</p>
<h3 id="">你可以在家工作</h3>
<p>编程的好处之一是你可以在家（或任何地方）工作，并且可以远程就业。这意味着你不必为了更有趣的工作或更好的报价而搬到其他地方。</p>
<p>在疫情期间，许多公司提供了在家工作的机会，许多公司在疫情后仍将继续提供这一机会。</p>
<p>这对许多人来说是一个极大的安慰，因为它省去了每天去办公室的需要，减少了额外的租金，避免了与家人分离的生活。</p>
<h3 id="">你可以有灵活的日程安排</h3>
<p>不同的人在工作之外有不同的责任，包括家庭需求、医疗预约或某些时间的各种承诺，这些承诺不能推迟。</p>
<p>所以对许多人来说，有一个灵活的时间表，甚至在某些时间离开工作是必要的。许多开发人员在工作时间表上能够有这种灵活性。</p>
<h3 id="">你可以与聪明的人合作并向他们学习</h3>
<p>如果你在一个团队中，可能会有人比你学习过更多不同领域的技术。他们可能在各种之前的项目中积累了丰富的经验。这将为你提供许多学习和合作的机会。尽可能利用这些机会。</p>
<p>你可能会有来自德国、新加坡或巴西的团队成员，或世界上任何地方。通过在同一个项目上工作，你有机会受益于他们的知识、他们对问题的处理方式以及他们的创造性解决方案。</p>
<h3 id="">工资通常非常高</h3>
<p>程序员的薪水通常比许多其他职业要高。</p>
<p>这不仅是一个小差异——在大多数国家，甚至是全部国家，程序员的平均工资显著高于国家平均水平。</p>
<p>这一趋势反映了全球就业市场对编程技能的高需求和重视。</p>
<p>除了获得丰厚报酬的机会外，根据你的工作，还有加薪或其他财务激励/福利的机会。</p>
<p>此外，许多科技公司为员工实施了奖金计划。这些奖金是为了实现业务目标、卓越表现或极其敬业的工作而发放的。</p>
<p>根据公司的政策，奖金可以发放给个人或团队。</p>
<p>因此，根据个人或团队的成就、获取大客户或完成成功项目，员工可能会获得额外的奖金形式的报酬。</p>
<p>这对许多程序员来说是一个重要的激励因素。</p>
<h3 id="">你可以经常享受带薪休假</h3>
<p>尽管我们可能有动力工作，并热衷于将我们的想法变成代码从而变成现实，但我们是人类，需要休息和放松。所以请确保抽出时间与日常工作脱离。</p>
<p>换句话说，休息对每个人都有好处，尤其是对可能整天都在工作和压力中的程序员来说。</p>
<p>一般来说，开发人员的带薪休假相当宽松，允许他们全年休假。还有些公司提供长时间休假的机会，只要这不影响项目和整个团队的工作。</p>
<p>对于其他职业的人来说，休假并不总是容易的，因为他们往往没有那么大的灵活性，也没有那么宽松的带薪休假。</p>
<p>这些只是编程可能在职业上对你合适的部分原因。</p>
<p>但公平起见，让我们也考虑一些缺点，看看它们是否会成为你选择编程的障碍。</p>
<h2 id="">编程工作的潜在挑战</h2>
<p>也许你没有预料到这本书会讨论这个问题，这本书旨在激励你考虑成为一名开发人员。</p>
<p>但我认为分享潜在的缺点同样重要，以帮助你做出明智的决定。</p>
<p>这里，我只会讨论一些编程职业带来的缺点。你可能不会具体经历所有这些，也不能因此减少它们发生在你身上的可能性。但如果你知道它们，也许你可以更容易地避免它们。</p>
<h3 id="">编程可能会带来压力</h3>
<p>也许你有机会与其他开发人员交谈，他们告诉你编程是有压力的。这可能是多种情况造成的。</p>
<p>例如，如果你专注于解决某个特定的问题，你可能会犹豫不愿意离开你的椅子走动一下，这有助于缓解压力。但你不想在解决问题之前停下来。这会增加你的压力。</p>
<p>那么，你能做些什么来缓解压力或释放问题带来的情绪负担呢？首先，最好做一些身体运动，包括从椅子上站起来，在办公室（或你的家，或你工作的任何地方）四处走动，去户外呼吸新鲜空气，暂时改变环境。</p>
<p>记住：压力既会影响你清晰思考（这会帮助你更容易找到问题的解决方案），又会消耗你的所有精力。这些都可能导致你的心理和情绪状态恶化。</p>
<h3 id="">你需要不断学习</h3>
<p>学习是进步的唯一途径。因此，如果你总是感到学习新事物的压力，这也是一个很好的机会，你可以利用它来提升你的职业生涯。</p>
<p>新的技术工具、编程语言和平台不断涌现。你可能忙于处理工作之外的承诺，这也会占用你的时间和精力。</p>
<p>无论你在编程方面有多少经验，唯一不变的是不断学习的需要。学习新事物有助于你跟上就业市场的步伐，了解客户的需求，并开发自己的产品。</p>
<p>但也许你不喜欢总是学习新技能的压力。</p>
<p>你可能是那种一旦进入一份工作，就希望感到舒适和安全的人。这是可以的，但可能会导致抱负较低，目标较少或不那么令人兴奋。</p>
<p>所以，如果你不总是想学习新技能，这可能是技术领域的一个负面方面和不适合的负担。但我希望你能将其视为一个值得挑战的机会，而不是编程的缺点。</p>
<h3 id="">你有很大的责任</h3>
<p>你的开发工作可能会被很多人使用。它可能会对他们产生积极的影响，使他们的生活更轻松。</p>
<p>但这种巨大的力量伴随着巨大的责任。例如，如果你未能发现程序中的错误，可能会对许多人产生负面影响。</p>
<p>这与设计手表时出现的问题不同，例如手表有划痕或皮带破裂。如果你发布一个有数万（甚至更多）人使用的应用程序——比如一个医疗设备——它包含错误，可能会危及人们的生命。</p>
<p>这可能看起来有些夸张，但值得记住的是，许多医院计算机上医生和医务人员使用的程序可能存在错误或漏洞。结果，这个错误可能导致医生做出错误的诊断和错误的治疗，这对患者来说可能非常有害，甚至致命。</p>
<p>所以，作为开发人员，你需要认真对待自己的责任，认真细致地完成工作。</p>
<h3 id="">你可能需要加班</h3>
<p>这不仅仅是程序员特有的情况，因为其他工作的人也经常需要加班。但这对有额外责任的开发人员来说可能特别困难。</p>
<p>作为开发人员，你可能需要因为许多原因加班，例如：</p>
<ul>
<li>你需要在很短的期限内完成一项新任务、新功能或客户的整个项目。</li>
<li>你编程的一些服务失败了，需要立即修复，以便客户的服务或工具不会中断。你可能需要在下班后、周末或官方假期在电脑前修复它。</li>
<li>一个你使用的编程库中出现了安全问题，你需要解决它，以便你的客户和用户不受此问题的影响。错误是不可避免的，尤其是在编程中，但错误各不相同，有些可能非常有害，而有些可能甚至不会被注意到。</li>
</ul>
<p>只要确保你与团队、客户和经理设定边界和期望，以免总是加班。</p>
<h3 id="">你必须长时间坐在电脑前</h3>
<p>开发人员经常长时间坐在椅子上，往往没有足够的体力活动。这可能会导致你开始出现背部或关节疼痛、麻木、体重增加或其他潜在的有害健康问题。</p>
<p>或者，当你集中精力调试问题时，你可能有时甚至忘记在电脑前闭上眼睛。这当然不健康，因为它会伤害你的眼睛。</p>
<p>此外，坐在离电脑很近的位置，通常不到一米，你可能会长时间固定眼睛在同一个位置，这对眼睛也有害。</p>
<p>为了避免这些问题，你可以去健身房锻炼，按照 YouTube 上的指导在家做轻松的运动，并通过更频繁地活动身体，例如从椅子上站起来、在办公室走动、吃健康的食物、拉伸等来保持健康。</p>
<h3 id="">你的体重可能会增加</h3>
<p>许多程序员在工作中感到压力。因此，他们为了减轻压力而吃得比需要的更多——他们可能甚至没有注意到由于压力而暴饮暴食。</p>
<p>再加上你可能会长时间坐着并且吃得比需要的多，你可能会开始增加体重和失去肌肉。</p>
<p>为了避免不必要的体重增加，请注意你吃什么和吃多少。你可以尝试减少不健康的脂肪和糖分摄入。你还可以做一些身体锻炼，确保少量多次地进食。</p>
<p>这些只是程序员可能面临的一些挑战。但希望现在你了解这些挑战后，可以找到避免或应对它们的方法。</p>
<h2 id="">为什么软件工程师薪水这么高？</h2>
<p>我们工作的原因之一是赚取金钱来支付开支并确保我们可以过上愉快和有尊严的生活。</p>
<p>从小我们就必须学习，完成教育并获得经验，以便更容易找到好工作并赚到好钱。</p>
<p>既然你在读这本书，你可能已经听说软件工程师的薪水相比于许多其他职业要高很多。</p>
<p>即使是那些没有正式教育且工作经验相对较少的程序员的平均工资，通常也远高于其他领域的人的平均工资。</p>
<p>有很多原因，但在这里我将讨论我认为的一些主要原因。</p>
<h3 id="">对软件工程师的需求增加</h3>
<p>在当今世界，几乎每家公司都需要软件工程师。这是因为技术在我们的日常生活中占有重要地位。</p>
<p>我们在手机、汽车和工作中使用技术。健康、教育和娱乐等领域的公司需要软件工程师来开发和维护他们的计算机程序。</p>
<p>因为这么多公司需要这些技能，所以有很多软件工程师的工作。这使得公司提供高薪来吸引最好的软件工程师为他们工作。</p>
<p>此外，成为一名软件工程师并不容易。这需要大量的学习和实践。</p>
<p>技术不断变化，所以软件工程师必须不断学习新事物。并不是每个人都能很好地做到这一点，所以软件工程师并不多。</p>
<p>这意味着因为很多公司需要软件工程师，而能够胜任工作的软件工程师却不够多，所以他们的工资很高。</p>
<p>简单来说，软件工程师赚钱很多，因为他们的需求量很大，而能够胜任工作的人却不多。</p>
<h3 id="">你帮助将想法变为现实</h3>
<p>当你想建造一所房子时，你首先会寻求建筑师的帮助，他会到你的土地上，分析环境，然后经过一段时间，为房子的每一部分提出详细的计划。</p>
<p>然后，这个计划会由建筑工程师接手，他管理一组工人和整个施工过程，直到房子建成并准备好使用。</p>
<p>这是需要大量培训和专业知识的高技能工作。成为开发人员也是一样的。你得到相对较高的报酬，因为这反映了你所拥有的高水平技能以及完成工作所需的大量努力和工作。</p>
<p>软件工程师能够将客户的想法变成计算机程序，这个程序可以为全世界的人们带来好处。这是一项非常有价值的技能，因此得到了相应的奖励。</p>
<h3 id="">你的解决方案可以连接全世界的人</h3>
<p>当你想到一条主要公路时，考虑它如何连接不同的地区并改变旅行和商业。</p>
<p>例如，一条主要公路可能连接两个主要城市，大大增加了游客和商务旅行之间的流量。</p>
<p>建造这样一条公路需要大量投资和努力，但一旦完成，它可以为人们节省大量时间，并开辟新的机会。</p>
<p>这个概念类似于计算机程序的创建。</p>
<p>当一个程序被开发出来时，它有可能连接全世界数百万不在同一个国家甚至同一个大陆的人。</p>
<p>以社交媒体应用为例。它们是为全球使用而设计的计算机程序，帮助你、你的家人和朋友进行交流，结识新朋友，或者了解最新的新闻。</p>
<p>或者考虑 Google 的搜索引擎，它每天处理超过 35 亿个查询，涉及各种主题。只要有互联网连接，它可以帮助世界各地的人们解决问题并学习新事物。</p>
<p>这些程序就像一条建造良好的公路一样，促进了无数个人的连接和互动，使生活变得更高效、更连接。</p>
<h3 id="">软件工程师在许多领域工作</h3>
<p>软件工程师的一个特别之处在于他们可以在许多不同的领域工作。他们不仅仅局限于一种工作。</p>
<p>这非常重要，也是他们获得高薪的原因之一。</p>
<p>想象一个软件工程师为医生办公室开发一个程序来跟踪患者。</p>
<p>然后，也许下周，他们可能为一家酒店制作一个预订系统，或者帮助一所学校管理其信息。</p>
<p>软件工程师可以通过开发计算机程序来帮助许多不同的企业解决问题，使事情变得更容易。</p>
<p>不同的公司，比如健康、酒店或学校，可能对技术了解不多。但他们知道技术可以帮助他们做得更好。</p>
<p>所以，他们愿意支付高薪给软件工程师，以便制作好的技术。</p>
<p>这是因为软件工程师能够做很多改变和改善不同业务运作的事情。</p>
<p>这不仅仅是编写代码；这是关于制作真正有助于业务的工具。</p>
<h3 id="">你不断提升自己的技能</h3>
<p>许多开发人员不断努力开发新工具，以便于他们的日常工作，使其更轻松或更省时。</p>
<p>他们编写程序来为他们执行重复性任务，这样他们可以节省时间，用于为项目实施逻辑和更复杂的解决方案。</p>
<p>因此，作为程序员，你将始终提升自己的技能，并且在提供问题解决方案方面变得越来越快。你将采用最强大的工具，帮助你更快地完成工作并完成更多任务。</p>
<p>一个可能需要更长时间完成的项目，现在你可以通过使用这些你已经学会的新工具在更短的时间内完成。这意味着使用你作为程序员的服务的企业能够更快地向市场推出有用的产品，更好地服务客户。</p>
<p>换句话说，软件工程师薪水如此高，是因为他们拥有如此专业和有价值的技能，可以帮助世界各地的许多人。</p>
<h1 id="">如何为你的编程之旅做准备</h1>
<h2 id="">你的自我意识是你的敌人</h2>
<p>当你开始考虑开始你的编程之旅时，很容易感到不知所措。</p>
<p>你可能会想象 Google 或 Amazon 那样复杂的系统和软件，并怀疑自己是否能够理解这些复杂性。</p>
<p>通常，当我们着手成为熟练的程序员时，我们发现最大的障碍不是代码本身，而是我们的自我意识。</p>
<p>这里所说的自我意识，是指对自己重要性的盲目信念：我们的傲慢和自我中心的野心。</p>
<p>这就像我们内心的一个顽固声音，坚持要成为最好的，而不考虑学习编程的协作性、挑战性和反复性。</p>
<p>自我意识会误导我们，让我们认为自己比实际知道的更多，阻碍我们有效学习和合作。</p>
<p>它阻碍了我们真正掌握编程、建立与同伴学习者的建设性关系，以及识别或创造成长机会。</p>
<p>自我意识在职业生涯中始终是一个威胁，尤其是在我们开始学习编程的新事物时。</p>
<p>它可能会阻止我们构建伟大的软件，推进我们的学习目标，并从挫折中恢复。</p>
<p>为了防范自我意识，我们需要在学习旅程的每个阶段意识到它的影响。</p>
<blockquote>
<p>“知己知彼，百战不殆。不知彼而知己，一胜一负。不知彼不知己，每战必殆。” ——孙子</p>
</blockquote>
<h3 id="">如何在学习编程的早期阶段克服自我意识</h3>
<p>你可能以高昂的热情开始，也许受到了自学成才的程序员成功故事或成为技术奇才的吸引。</p>
<p>在这种情况下，自我意识可能会让你相信成功会轻而易举地到来，你会迅速掌握编程语言或跳过通常的学习曲线。</p>
<p>记住，编程中最令人印象深刻的成就是通过奉献和努力实现的。考虑一下 WordPress、Microsoft 和 Google 背后的建设者。</p>
<p>他们的成功故事充满了不懈的努力，而不仅仅是天赋或运气。</p>
<p>在开始编程旅程时，不要陷入高估自己能力的陷阱。致力于这个过程，花时间练习，接受学习的磨砺。</p>
<p>合作是关键，因为许多突破性的项目都是团队努力的结果。</p>
<p>考虑主要的科技创新者如何合作：Google 的创始人在斯坦福大学的计算机科学系相遇，Microsoft 的创始人比尔·盖茨和保罗·艾伦共同合作，WhatsApp 也是合作的产物。</p>
<p>学习编程也是如此——这是关于加入一个社区，分享知识，共同成长。</p>
<h3 id="">自我意识与持续学习</h3>
<p>即使在找到第一份编程工作或完成几个项目之后，也不要让自我意识让你认为你已经学到了所有的知识。</p>
<p>技术领域不断发展，持续学习至关重要。</p>
<p>记住，编程的旅程没有终点。它是一个不断增长和适应的过程。</p>
<p>你的自我意识可能会让你抵制新挑战，避免学习新语言或框架，或在遇到困难时避免寻求帮助。</p>
<p>然而，这些正是丰富你的编程旅程并最终掌握编程的经历。</p>
<p>历史上有许多例子表明，最初的失败或挫折导致了巨大的成功。</p>
<p>比尔·盖茨和保罗·艾伦在创立 Microsoft 之前有过失败的尝试，许多成功的应用程序和平台都是在之前不成功的尝试中诞生的。</p>
<h3 id="">拥抱谦逊和毅力</h3>
<p>要在你的编程旅程中茁壮成长，谦逊和毅力是你最好的盟友。接受失败和挑战是过程的一部分。将它们视为踏脚石，而不是障碍。</p>
<p>保持开放的心态，持续学习，寻求反馈，记住合作可以增强你的成长。</p>
<p>随着你的进步，记住自我意识是学习的敌人。保持脚踏实地，专注于过程，珍惜成为熟练程序员的旅程。</p>
<p>你对编程世界的独特贡献不在于一开始就成为最好的，而在于开放成长，从每一次经历中学习。</p>
<blockquote>
<p>“第一原则是你不能欺骗自己——而且你是最容易欺骗自己的人。”——理查德·费曼</p>
</blockquote>
<p>在学习编程时，让你的好奇心和对这门技艺的热情成为你的指南，而不是你的自我意识。</p>
<p>专注于工作，专注于学习过程，享受编程的乐趣。</p>
<p>在早期识别自我意识的声音，并用纪律、谦逊和对终身学习的承诺来对抗它们。</p>
<h2 id="">对你的学习负责</h2>
<p>不要因为在学习编程时的理解不足或遇到困难而责怪他人。简单地接受你是你生活中所有问题和困难的共同因素。</p>
<h3 id="">你不理解某一课吗？</h3>
<p>不要责怪课程、书籍或讲师。学习是你的责任。</p>
<p>每个老师都尽力而为，而且我们生活在一个有许多选择可以选择和学习的时代。</p>
<p>所以没有借口。如果你努力工作，你会到达那里。</p>
<h3 id="">你最近是否发现你写的一段代码在项目中没有按预期工作？</h3>
<p>尽管这可能是罕见的情况或你可能无法预测会发生，但你仍然应该承担责任。</p>
<p>首先，承认你犯了错误。然后，去弄清楚如何解决问题。</p>
<p>利用这个机会学习并记录出错的地方以及你可以在未来做得更好的地方。</p>
<h3 id="">你觉得是否自己无法跟上学习新事物的步伐？</h3>
<p>我相信你已经知道这也是你的责任。</p>
<p>这可能很难，而且非常耗时，尤其是如果你有孩子或其他家人需要照顾，同时还希望有社交生活的话。</p>
<p>然而，你的成长是你的责任。</p>
<p><strong>你必须承担这个责任。</strong></p>
<p>你应该尝试每周抽出几次时间来提高你的技能，无论是在你的日常工作中没有任务时你有空学习，还是在离开工作之前、在晚上或任何对你来说现实的时间。</p>
<p>你可以尝试每天早起一小时，在工作前投资那段时间来学习新事物，或者你也可以在周日早上抽出几个小时来做这件事。</p>
<h2 id="">我害怕编程--我该怎么办</h2>
<p>开始编程旅程可能令人生畏，感到害怕或自我怀疑是很自然的。但请记住，即使是科技和科学领域中最成功的人物也面临过这些挑战。</p>
<p>考虑一下 Google 联合创始人谢尔盖·布林。他取得了显著的成功，但他也谈到过感到像冒名顶替者，怀疑自己对科技行业的贡献。他的故事表明，即使在高水平的成就中，这种感觉也是正常的。</p>
<p>前 Facebook 首席运营官谢丽尔·桑德伯格也是科技行业的领袖，她也谈到了冒名顶替者综合症的困扰。尽管她取得了巨大成就，她也经历了自我怀疑和质疑自己能力的时刻。这强调了每个人，无论他们的成功如何，都可能会经历这些感觉。</p>
<p>天体物理学家尼尔·德格拉斯·泰森也坦率地谈到了自己在科学职业生涯中经历的冒名顶替者综合症。他的坦诚有助于揭开进入新挑战领域所伴随的恐惧的神秘面纱。</p>
<p>著名作家和诗人玛雅·安杰卢博士也表达过类似的感受。尽管她获得了无数的荣誉，她也感到对自己价值和成就的怀疑。她的旅程是克服自我怀疑实现伟大的鼓舞人心的例子。</p>
<p>韦恩·格雷茨基的名言“你错过了所有你不尝试的机会”在这里产生了深刻的共鸣。如果恐惧阻碍了你，你永远不会发现你在编程中的潜力。</p>
<p>开始编程之旅可能令人望而生畏，对失败的恐惧是常见的。然而，关键是尽管有这些恐惧，也要开始。记住，你所仰慕的科技专家和领袖们也是从初学者开始的，就像你一样。他们面对恐惧，犯错，并从中学习。</p>
<p>所以，如果你的目标是成为编程或软件工程领域的佼佼者，接受挑战。开始学习，不要让恐惧或自我怀疑阻碍你。</p>
<p>每个人的旅程都是从第一步开始的，感到不确定只是成为技能和信心的过程的一部分。</p>
<h1 id="">学习编程的策略和技巧</h1>
<h2 id="">你能在一个晚上学会编程吗？</h2>
<p>一个 bug 使得 Therac-25 放射治疗机<a href="https://www.newscientist.com/gallery/software-bugs/">导致死亡</a>五名患者在接受大量 X 射线后死亡。</p>
<p>Knight Capital 在半小时内因为一个软件错误<a href="https://www.newscientist.com/gallery/software-bugs/">损失了 5 亿美元</a>，该错误允许计算机在无人监督的情况下卖出和买入数百万股股票。</p>
<p>这些和许多其他故事告诉我们，看似不重要的错误实际上可以引发灾难。</p>
<p>软件变得越来越重要——这意味着开发人员需要非常小心，并且非常擅长他们的工作。</p>
<h3 id="">那是否可以在一个晚上学会编程呢？</h3>
<p>虽然听起来很搞笑，但在超过五年前的 Quora 上有人问过类似的问题。</p>
<p>不幸的是，我现在找不到那个确切的问题了，但自那时起它就印在我的记忆里。</p>
<p>也许，提问者是在开玩笑，或者第二天有考试，希望能得到鼓励的答案以便通宵学习。</p>
<p>我不记得其他答案了，但我在那看到一个非常智慧且相当有趣的答案。</p>
<p>这个答案大概是这样的：</p>
<blockquote>
<p><em>带上一台笔记本电脑去北极。那里的一夜持续 6 个月。这就是你在一个晚上学会编程的机会。</em></p>
</blockquote>
<p>我们生活在一个希望一切都在几秒钟内完成的时代。</p>
<p>我们想要快餐，快车，六天内练出六块腹肌，等等。</p>
<p>这就是我们大多数时候的心态，我们也期望在其他领域有同样的结果。</p>
<p>但真正的掌握来自大量的工作和奉献。</p>
<p>以 Google 的研究主管 Peter Norvig 为例，他<a href="https://norvig.com/21-days.html">建议</a>你在十年内学习编程，因为仓促学习是不值得的：</p>
<blockquote>
<p>_“在 24 小时内你没有时间编写几个重要的程序，并从中学习成功和失败的经验。你没有时间与一位有经验的程序员一起工作，并了解在 C++环境中生活是什么样的。简而言之，你没有时间学到很多东西。</p>
<p><em>所以这本书只能谈论表面的熟悉，而不是深刻的理解。正如亚历山大·蒲柏所说，浅尝辄止是危险的。”</em></p>
</blockquote>
<p>如果你告诉人们这一点，他们可能不喜欢，但这是实际情况。</p>
<p>你不能仅仅从在控制台打印几个“Hello World”语句，到几天后构建下一个 Google。</p>
<p>我并不否认你可以在几小时内实现一个非常好的应用程序——但具备做到这一点的能力不会来得那么快。</p>
<p>当然，你可能听说过那个<a href="https://dev.to/florinpop17/10-javascript-projects-in-10-hours-coding-challenge-316d">一坐下就在 10 小时内实现了 10 个应用程序的开发者</a>。但这不是一夜学习的结果。他在那之前付出了很多努力并学到了很多。</p>
<p>要真正学好一样东西需要时间。</p>
<p>你做的越多，你就越有可能变得更好。你练习的越多，你就越能够提高你的表现——这个循环会不断重复。</p>
<p>现在你已经读完并希望内化了这些内容，不要因为漫长的旅程而感到不知所措。</p>
<p>威尔·史密斯很好地描述了这一点：</p>
<blockquote>
<p>“你不会一开始就打算建造一堵墙。你不会说‘我要建造有史以来最大的、最棒的、最伟大的墙。’你不会从那里开始。你会说，‘我要把这块砖砌得尽善尽美。’你每天都这样做。很快你就有了一堵墙。”</p>
</blockquote>
<p>现在，与其问自己是否能在一个晚上学会编程，不如问一个更好的问题：</p>
<p><strong>我今晚能学到的一个小但有价值的东西是什么？</strong></p>
<h2 id="">避免教程地狱</h2>
<p>你是否曾经花费数小时观看教程视频，然后觉得自己像个专家，却发现自己实际上无法实现教程中展示的内容？</p>
<p>这是一个常见的陷阱，被称为“教程地狱”。它指的是当你通过阅读大量教程而没有真正尝试构建某些东西时，可能会产生的虚假学习感。</p>
<p>当你只看教程而不实践时，你可能会认为自己在学习，但实际上你并没有获得完整的体验。</p>
<p>仅仅被动地观看某些东西并不等于真正理解并能够使用这些知识。</p>
<h3 id="">通过编程来学习编程</h3>
<p>许多人尝试仅通过观看视频或阅读文章来学习编程。</p>
<p>但如果你真的想学会编程，你必须亲自动手编写代码。</p>
<p>仅仅坐着看别人做是不够的。<strong>你需要自己编写代码。</strong></p>
<p>这是将视频中的理论知识转化为实际技能的唯一方法。</p>
<h3 id="">超越被动学习</h3>
<p>当深入学习一个特定的框架或技术时，很容易陷入被动观看或阅读的陷阱。</p>
<p>相反，你可以采取积极的方式。</p>
<p>想一个你感兴趣并想要创建的项目。这可以是一个简单的网站或一个小应用程序。关键是选择一些让你兴奋并激励你学习的东西。</p>
<p>你选择的项目将成为你的测试场。你将在这里应用你从教程中学到的一切。</p>
<p>这种实践是无价的。</p>
<p>当你在项目上工作时，你会遇到实际问题和挑战。</p>
<p>解决这些问题将加深你对编码概念和技术的理解。你会通过 Google 搜索、研究、尝试和失败以及再次尝试学到很多东西。</p>
<p>正是在面对和克服这些挑战时，真正的学习发生了。</p>
<p>记住，掌握任何技能的道路，尤其是编程，在于积极参与。</p>
<p>观看教程是一个很好的开始，但实践使你熟练。通过实践学习。</p>
<p>你的个人项目不仅仅是一个测试，而是通向深入理解和技能发展的旅程。</p>
<p>所以，关闭视频播放器，打开你的代码编辑器，开始构建。</p>
<p>你真正的学习之旅从你编写的第一行代码开始。</p>
<h2 id="">如何通过费曼技巧理解复杂主题</h2>
<p>在软件工程领域，知道某件事的名称和真正理解其工作原理之间存在巨大差异。</p>
<p>你可能知道某台机器或某个软件的名称，但你是否真的理解它是如何运作和完成任务的？</p>
<p>在如此复杂且不断发展的领域中，这种区别至关重要。</p>
<p>通过“教学反馈”技巧，可以有效地弥合表面知识和深刻理解之间的差距。</p>
<p>这种方法通常与著名物理学家理查德·费曼相关，围绕着将你学到的东西教授给他人的想法。</p>
<h3 id="">什么是“教学反馈”技巧？</h3>
<p>想象一下，你在向一个对软件工程不太熟悉的朋友或同事解释你学到的新概念或工具。这可以是一个编程概念，一种编码语言，或者是区块链或机器学习等高级主题。</p>
<p><strong>首先，开始解释</strong>：从将主题分解成简单的术语开始。你的目标是使其对几乎没有背景知识的人也能理解。这种练习迫使你澄清你的想法并巩固你的理解。</p>
<p><strong>接下来，识别知识中的空白</strong>：在解释过程中，注意你踌躇或不确定的时刻。这些是你的理解仍然浅显的领域。返回你的学习材料，无论是书籍、文章还是在线资源，深入研究这些主题。</p>
<p><strong>记住，简洁是关键</strong>：在你的解释中，避免使用术语和复杂的语言。能够在不失去其本质的情况下简化概念，是一种真正理解的标志。这种方法不仅对你的学习者有益，还能强化你对该主题的掌握。</p>
<p><strong>分享可以巩固你的知识</strong>：一旦你对自己的解释感到满意，考虑更广泛地分享你的新知识。写博客文章、制作笔记或甚至录制视频都可以进一步巩固你的理解，并对他人有益。</p>
<p><strong>收获的好处</strong>：这种教授他人的技巧不仅能加深你的知识，还能增强你作为软件工程师的效率。这是一种强大的学习工具，验证了“教就是学两次”的说法。</p>
<p>记住，在软件工程中，真正理解的考验在于你能否用简单、易懂的语言传达复杂的想法。</p>
<p>你解释得越有效，表明你对其理解得越透彻。</p>
<p>即使你的学生是一个虚构的角色，拥抱教师的角色，你的理解和熟练度会随之增长。</p>
<p>这种方法不仅仅是为了获得知识——而是为了掌握它。</p>
<h2 id="">不要记忆语法</h2>
<p>假设你搬到一个新城市，不知道最近的杂货店在哪里。你不会责怪自己——这是意料之中的。你只需使用 Google 地图找到它。</p>
<p>在你去过几次之后，很可能你不再需要使用 Google 地图了（除非你想查看交通情况或查看路线上是否有事故——诸如此类的事情）。</p>
<p>因此，你自然会随着时间的推移学会东西的位置——但这并不是你故意尝试记住每条道路，每个到达某个目的地的可能路径。</p>
<p>有时你可能只想去某个地方一次。</p>
<p>这与编程语言中你可能需要使用的某些方法是一样的。新软件开发人员可能会因为没有记住足够的语法而感到难过——他们仍然需要参考文档。</p>
<p>他们认为这是他们是糟糕开发人员的标志。</p>
<p>以下是你在开始编程之旅时可能会有的一些常见问题：</p>
<ul>
<li>我如何能学会所有这些语法？</li>
<li>我需要多长时间才能掌握它并在不参考文档的情况下编写代码？</li>
</ul>
<p>然后，当你能够记住一些常用的语法时，你可能会认为自己已经成为了优秀的程序员。</p>
<p>你会觉得你能记住的语言或编程语言和框架的数量真正重要。</p>
<p>为了让事情更清晰，让我们比较一下在不同编程语言中找到字符串长度的语法：</p>
<ul>
<li><code>seq.length</code>，JavaScript 列表，Java 数组。</li>
<li><code>seq.size()</code>，Java 序列，jQuery 表达式（已弃用）。</li>
<li><code>len(seq)</code>，Python。</li>
<li><code>seq.count()</code>，Django 查询集。</li>
<li><code>SeqType'Length</code>，Ada 数组。</li>
<li><code>length seq</code>，Haskell。</li>
<li><code>(count seq)</code>，Clojure。</li>
<li><code>sizeof(seq)/sizeof(seq[0])</code>，C，静态分配。</li>
<li><code>strlen(seq)</code>，C，空终止。</li>
</ul>
<p>如你所见，每种语言或技术都有其自己的方式来找到字符串的长度。这应该向你表明，记住 12 种不同方式的同一个函数真的很困难。</p>
<p>使用过多种编程语言的开发人员不太可能记住过去使用过的所有语法。他们甚至可能一开始就懒得去学。那么这是为什么呢？人们究竟是如何编写代码的呢？</p>
<h3 id="">语法重要到必须记住吗？</h3>
<p>为了回答这个问题，让我们看看一些高级开发人员怎么说。</p>
<p>这里有一位 Google 高级开发人员的<a href="https://twitter.com/tdierks/status/835912924329836545">评论</a>：</p>
<p>“你好，我叫 Tim。我是 Google 的负责人，有超过 30 年的编码经验，但我需要查找如何获取 Python 字符串的长度。”</p>
<p>这是另一位开发商业航空控制系统的开发人员的<a href="https://twitter.com/jp10k/status/835942380163457024?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E835942380163457024%7Ctwgr%5E6dada45bde9adb460de96219170b9a9a0224f802%7Ctwcon%5Es1_c10&amp;ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Fjp10k%2Fstatus%2F835942380163457024image%3D__hrp%3DeyJtdXRlciI6ZmFsc2UsIndhaXRGb3JEb2N1bWVudEJvZHkiOnRydWUsIndhaXRGb3JEb2N1bWVudFJlYWR5IjpmYWxzZSwibm9QYXRjaGVzIjp0cnVlLCJ3aWR0aCI6IjEwMCUiLCJoZWlnaHQiOiIxMDAlIiwiZW5naW5lTmFtZSI6ImVuZ2luZS0wLjEuMCIsImZyYW1lTmFtZSI6ImVuZ2luZS0wLjEuMDoxMTE2OTAxNjk0In0%3D">评论</a>：</p>
<p>“你好，我叫 JP。我把 Node.js 放进了一架商用飞机。我仍然不知道.substr()和.substring()的区别。”</p>
<p>JP 继续对之前的推文进一步评论道：</p>
<p>“@tdierks 即使是这篇文章，我也不得不查找如何编写带有或不带驼峰命名法的子字符串。”</p>
<p>Jon，Phunware 的安卓开发负责人，说他无法在不复制粘贴 Stack Overflow 代码的情况下读取输入流（详见<a href="https://twitter.com/JonFHancock/status/834178169980678144?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E834178169980678144%7Ctwgr%5E119908340c882f5ed0cbe4930bb1f24265742d67%7Ctwcon%5Es1_c10&amp;ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Fjonfhancock%2Fstatus%2F834178169980678144image%3D__hrp%3DeyJtdXRlciI6ZmFsc2UsIndhaXRGb3JEb2N1bWVudEJvZHkiOnRydWUsIndhaXRGb3JEb2N1bWVudFJlYWR5IjpmYWxzZSwibm9QYXRjaGVzIjp0cnVlLCJ3aWR0aCI6IjEwMCUiLCJoZWlnaHQiOiIxMDAlIiwiZW5naW5lTmFtZSI6ImVuZ2luZS0wLjEuMCIsImZyYW1lTmFtZSI6ImVuZ2luZS0wLjEuMDoxMTE2OTAxNjk0In0%3D">评论</a>））。</p>
<p>另一位 Tim 对原 Tim 的帖子<a href="https://twitter.com/timbray/status/835933619344429056?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E835933619344429056%7Ctwgr%5E63388c8dc8ce43932c19c9cdb105d65ade61807d%7Ctwcon%5Es1_c10&amp;ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Ftimbray%2Fstatus%2F835933619344429056image%3Dhttps3A%2F%2Fi.embed.ly%2F1%2Fimage3Furl3Dhttps253A252F252Fpbs.twimg.com252Fprofile_images252F421637246252FTim_400x400.jpg26key3Da19fcc184b9711e1b4764040d3dc5c07__hrp%3DeyJtdXRlciI6ZmFsc2UsIndhaXRGb3JEb2N1bWVudEJvZHkiOnRydWUsIndhaXRGb3JEb2N1bWVudFJlYWR5IjpmYWxzZSwibm9QYXRjaGVzIjp0cnVlLCJ3aWR0aCI6IjEwMCUiLCJoZWlnaHQiOiIxMDAlIiwiZW5naW5lTmFtZSI6ImVuZ2luZS0wLjEuMCIsImZyYW1lTmFtZSI6ImVuZ2luZS0wLjEuMDoxMTE2OTAxNjk0In0%3D">评论</a>道：</p>
<p>“你好，我也叫 Tim。我从 1979 年开始编程，我仍然需要一直查找 java.lang.String 方法。”</p>
<p>最后，我给你留下一位名叫 Umer 的评论：</p>
<blockquote>
<p>我写了 255 行代码，其中包括一个工作服务器和一个客户端。我查询了 23 次 Google，大多数落在 StackOverflow、Netty 4 网站、GitHub 和 JavaDocs 上。如果你做一下数学计算，平均每 10 行代码查询一次！我完全不知道。— <a href="https://tiantiankan.me/a/5cb4c6c2f4b9a5fab76893b2">Umer Mansoor</a></p>
</blockquote>
<p>这些见解应该给你勇气——你不必为记不住每个语法细节而感到羞愧。</p>
<p>这是许多初级开发人员可能关心的事情。事实上，你真的不必在学习过程中记住一切。</p>
<p>甚至技术招聘人员也不在乎这一点。Google 的一位工程总监对此的<a href="https://twitter.com/tdierks/status/836014459055443968?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E836014459055443968%7Ctwgr%5Ebc4ecbbf211fc241ea5a81dee2c330fa0dc86478%7Ctwcon%5Es1_c10&amp;ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Ftdierks%2Fstatus%2F836014459055443968image%3Dhttps3A%2F%2Fi.embed.ly%2F1%2Fimage3Furl3Dhttps253A252F252Fpbs.twimg.com252Fprofile_images252F867170721423908865252FReXcZP2R_400x400.jpg26key3Da19fcc184b9711e1b4764040d3dc5c07__hrp%3DeyJtdXRlciI6ZmFsc2UsIndhaXRGb3JEb2N1bWVudEJvZHkiOnRydWUsIndhaXRGb3JEb2N1bWVudFJlYWR5IjpmYWxzZSwibm9QYXRjaGVzIjp0cnVlLCJ3aWR0aCI6IjEwMCUiLCJoZWlnaHQiOiIxMDAlIiwiZW5naW5lTmFtZSI6ImVuZ2luZS0wLjEuMCIsImZyYW1lTmFtZSI6ImVuZ2luZS0wLjEuMDoxMTE2OTAxNjk0In0%3D">回答</a>是：</p>
<p>“我总是告诉候选人，我不在乎任何 IDE 可以帮助你完成的事情。”</p>
<p>这里是 Hacker News 上的<a href="https://news.ycombinator.com/item?id=11603078">评论</a>中的另一个引用：</p>
<blockquote>
<p>我不仅经常使用 Google，我还用它来搜索我自己过去写的东西。</p>
<p>我已经不记得多少次我为编程问题 Google 搜索，答案在我写的 Stack Overflow 页面上。如果是特别旧的答案，我完全忘记了，我甚至会想，“哇，这个天才听起来像我！”以及“这个白痴不知道他在说什么！”</p>
</blockquote>
<p>几年前，我在一个 Facebook 群组里读到一位高级开发人员提到，当招聘人员问他是否有某项技术的经验，而他没有时，他回答：“那只是另一个工具。”</p>
<p>他的意思是他可能没有机会使用过它，但他有信心可以学习它。</p>
<p>你可能不需要花费数月时间才能开始使用新工具。你可能只需要几个小时阅读其文档，然后在需要时进一步学习，而不需要记住所有内容。</p>
<p>你不期望在你开始旅程时所有红绿灯都亮着。你通过当前的绿灯，然后在红灯前停下来。等待绿灯亮起再继续前进。</p>
<p>如今，我们不断有新的语言和框架，或现有的重大变化，因此尝试记住语法既困难又不那么重要。正如一位博客文章的评论者巧妙地<a href="http://disq.us/p/17uk3bk">说</a>：</p>
<blockquote>
<p>“优秀的工程师知道如何提出好的查询。然而，面试官期望行走的字典。”</p>
</blockquote>
<p>所以，总结一下：<a href="https://www.freecodecamp.org/news/how-to-search-google-like-a-pro/">精通 Google 搜索</a>并随着学习的进展而学习 :)</p>
<h2 id="">保持一个待学习列表</h2>
<p>你可能听说过用待办事项列表来跟踪日常琐事或任务。</p>
<p>但作为一名软件工程师，学习与实际操作同样重要，"待学习"列表成为你成长和探索的路线图。</p>
<p>将待学习列表视为你在技术世界中的个人指南。</p>
<p>正如待办事项列表提醒你购买杂货或支付账单，待学习列表跟踪你想要探索的所有令人兴奋的技术事物。</p>
<p>这可能是一种风靡全球的新编程语言，一种可以改变你编程方式的革命性工具，或人工智能等领域的最新趋势。</p>
<p>你的待学习列表不仅仅是一个很酷的东西的集合——它是一组目标。</p>
<p>就像你的职业发展中的一个愿望清单，充满了等待你去冒险的挑战。</p>
<p>无论是掌握一种新的编程语言，阅读有见地的书籍，还是注册在线课程，这个列表都是你通向无尽学习世界的门票。</p>
<p>待学习列表保持你的好奇心。它就像一张藏宝图，X 标记了新知识的位置。</p>
<p>列表上的每个项目都是理解技术深层运作的踏脚石，而不仅仅是使用它。</p>
<p>这个列表也是一个激励因素。想象你学到的每一个新技能都是在游戏中升级，使你在工作中更有能力和技能。</p>
<p>它提醒你，作为软件工程师的旅程充满了等待实现的激动人心的里程碑。</p>
<p>记住，总有更多的东西可以学习，这是一件好事。</p>
<p>它让你保持谦逊和开放的心态，认识到技术世界是广阔且不断发展的，没有人知道所有的东西。</p>
<p>这种观点对持续成长至关重要。</p>
<p>当你完成待学习列表上的项目时，你会发现自己变成了一个解决问题的巫师。</p>
<p>每一个新的技能或知识都增加了你解决复杂挑战的能力，使你成为团队中无价的资产。</p>
<p>你学得越多，作为软件工程师的价值就越高。这意味着能够更有效和创造性地处理任务，提高你的生产力，使你在你的领域成为明星表演者。</p>
<p>你的待学习列表是你作为软件工程师的旅程中的强大工具。</p>
<p>它是一个与你一起成长和变化的活文档，反映了你的愿望和好奇心。</p>
<p>通过维护和更新这个列表，你确保你的软件工程之旅始终在前进，充满了持续的学习和个人成长。</p>
<p>所以，接受你的待学习列表，让它引导你在职业生涯中达到新的高度，让你在技术的动态世界中保持好奇、激励和不断发展。</p>
<h1 id="">编程的实际方面</h1>
<h2 id="">如何处理困难的项目</h2>
<p>像 Google、Amazon 或 WhatsApp 这样的大型软件项目，通常看起来像是现代奇迹。</p>
<p>它们可以令人敬畏，反映出复杂的工程和创新的想法。</p>
<p>如果你考虑到这些巨头背后的团队，自然会感到敬畏和恐惧。这些项目的规模和影响似乎令人难以承受。</p>
<p>记住，这些平台的建设者们在开始时可能也有类似的感觉。但他们没有让恐惧阻碍他们的进步。</p>
<p>相反，他们将其转化为生产力，一砖一瓦地奠定了最终成为技术里程碑的基础。</p>
<p>作为一名软件工程师，你可能不会立即被要求构建下一个全球技术现象，但每个项目，无论其规模如何，在开始时都可能显得令人生畏。</p>
<p>以下是帮助你处理最具挑战性的软件工程项目的路线图。</p>
<h3 id="">视野：从一开始就看到终点</h3>
<p>管理大型项目最关键的步骤之一是拥有清晰的愿景。这意味着要有一个明确的终极目标。这个愿景越清晰，导航越容易。</p>
<p>尝试用简单的术语来描述这个愿景，可能通过图表或简明的描述来实现。</p>
<p>你的目标应该是使这个愿景变得如此易懂，以至于任何人，无论他们的技术背景如何，都能理解。</p>
<p>例如，如果你正在开发一个复杂的 Web 应用程序，概述其核心功能。设想用户体验，界面以及定义你的应用程序的关键特性。</p>
<h3 id="">拆解它：逆向工程的艺术</h3>
<p>有了生动的终极目标，下一步是将这个愿景逆向转化成可操作的步骤。</p>
<p>这个过程包括将最终目标分解成较小的、可管理的任务。这些任务应该是量化的，使你能够有效地计划和安排它们。</p>
<p>在规划过程中，设定清晰的里程碑。这些是标志着你向最终目标推进的重大检查点。</p>
<p>以 Web 应用程序为例：从设计阶段开始，接着是前端开发，后端设置，功能集成，测试阶段和最终部署。然后你可以一个一个地处理这些阶段。</p>
<h3 id="">起点：第一个小步骤</h3>
<p>每个宏大的项目都从一个单一的，通常是小的步骤开始。</p>
<p>不要陷入认为你可以一口气完成整个项目的陷阱。大型项目需要时间、努力和毅力。</p>
<p>从一个可管理的任务或项目的组件开始。完成这个初始任务将提供一种成就感和动力。</p>
<p>进展，无论多么渐进，都是强大的推动力。它推动你向前，激励你解决项目的后续阶段。</p>
<p>如果你发现自己犹豫不决，可能是因为当前的任务看起来太令人生畏。在这种情况下，将任务进一步分解成更小、更可接近的部分。</p>
<h3 id="">反思性进展：复盘的重要性</h3>
<p>定期退后一步，审查你的进展。</p>
<p>这种做法对于确保你在正确的道路上朝着目标前进至关重要。</p>
<p>很容易陷入细节中，失去对整体目标的视野。定期审查有助于你重新调整你的努力与初始愿景保持一致。</p>
<p>这种复盘过程不仅仅是一个检查点。它是对你的方向和方法的战略评估。它可能导致课程修正，策略调整，甚至是对目标的重新评估。</p>
<h3 id="">前进的道路</h3>
<p>在软件工程中，遇到怀疑和陷入无所作为的循环是常见的。</p>
<p>等待完美的时刻或挑战自己缓解是不切实际的方法。相反，征服大型项目的关键在于接受责任并积极参与手头的任务。</p>
<p>无论项目的规模如何，通过仔细的计划、奉献精神和坚定的专注，总是可以完成的。</p>
<p>记住，在软件工程的领域，<em>唯一的出路就是前进的道路。</em></p>
<p>每一步，无论多么小，都是实现项目的进展。以承诺和决心接受每个阶段的旅程，观看你的雄心勃勃的项目如何变成已完成的现实。</p>
<h2 id="">如何选择要构建的项目</h2>
<p>当你开始学习并尝试应用你的技能时，你可能会有很多项目想法，迫不及待地想要开始构建。</p>
<p>也许你已经在项目管理工具中列出了这些想法，或者在笔记本中记下了它们。你有各种各样的应用程序概念、软件解决方案或编码实验让你感到兴奋。但有一个常见的挑战：决定首先要处理哪个项目。</p>
<p>这种犹豫不决可能导致拖延。你可能会发现自己选择更能立即满足的活动，避免对单个项目的承诺。</p>
<p>“也许有更重要的事情我应该做？”你想。“我应该开始这个应用程序还是那个自动化脚本？也许我应该再头脑风暴一些想法，总会有一个灵感。”</p>
<p>让我们暂时停下来，考虑一个可能会阐明这种困境的古老寓言。</p>
<h3 id="buridansass">从布里丹之驴（Buridan's ass）学到的教训</h3>
<p>有一个关于驴子的故事，它正好站在一些干草和水的中间。它无法决定先吃还是先喝，所以什么都没做，结果非常饥饿和口渴。</p>
<p>驴子没有想到先选一个，然后再做另一个。</p>
<p>作为软件工程师，我们经常在项目中面临类似的困境。我们有无数的想法和概念，但如果没有行动，任何一个都不会实现。</p>
<p>必须认识到，我们不能同时处理每个项目。就像我们不能同时在两个地方一样，我们也不能同时编写不同的应用程序。这种物理限制不应该阻碍我们实现目标的进展。</p>
<h4 id="">只需从一个项目开始</h4>
<p>这是完美的选择吗？也许不是。但这不是现在最重要的事情。</p>
<p>你选择的项目可能不是生死攸关的决定。选一个并开始。你总是可以稍后回到其他想法上。</p>
<p>首先列出应用程序或软件的功能。编写第一个函数或界面。庆祝这个进展，无论多么小。然后，继续逐步开发。</p>
<p>对其他项目重复这个过程。</p>
<p>不要让大量的选择阻碍你的进展。过度分析会导致瘫痪，阻碍你完成项目的进展。</p>
<p>停止过度思考。开始编程。</p>
<p>让世界受益于你的工作，一个个完成的项目。</p>
<h3 id="">如何克服拖延症</h3>
<p>这是软件工程师常见的挑战：“我知道我需要开始编程，但我就是无法开始。”</p>
<p>“空白的 IDE 屏幕很吓人。我无法让我的手指开始打字。”</p>
<p>考虑一下著名作家厄内斯特·海明威是如何应对写作障碍的：</p>
<blockquote>
<p>“有时当我开始一个新故事却无法进行时，我会坐在火炉前，挤压小橙子的皮到火焰边缘，观看它们产生的蓝色火花。</p>
<p>我会站着眺望巴黎的屋顶，思考‘别担心。你以前写过，现在也会写。你只需要写一句真实的句子。写下你知道的最真实的句子。’</p>
<p>最后，我会写一句真实的句子，然后继续写下去。”</p>
</blockquote>
<p>将这种方法应用到你的编程中。开始一个简单的功能或函数。</p>
<p>如果这是你今天完成的全部内容，那也没关系。持续的小步骤会带来显著的进展。</p>
<p>每天进行适度的编程可以保持一致性。而且通常，一旦你开始一个小任务，你会自然地进行到项目的更大部分。</p>
<h3 id="">历史上的灵感</h3>
<p>考虑一下艾萨克·牛顿在 1666 年黑死病封锁期间，从剑桥大学撤退到他家里。</p>
<p>没有现代工具或在线课程，牛顿利用这段时间深入研究复杂的数学问题，最终奠定了微积分的基础。</p>
<p>他的专注和奉献导致了突破性的发现。</p>
<p>在软件工程中，很容易陷入寻找完美工具或环境的困境中。</p>
<p>但请记住，真正的工作来自于奉献和努力，而不是拥有最新的技术或软件。</p>
<blockquote>
<p>“真正的专业人士不会躲在他们的工具后面——真正的专业人士使用他们周围的东西。业余爱好者才会试图在他们的工具上花时间——这都是为了逃避真正的工作。”——德里克·西弗斯</p>
</blockquote>
<p>让我们超越借口。让我们回到编程中。</p>
<h2 id="">通过从头开始构建来学习</h2>
<p>每次你开始一个新项目，想象它是你知识堡垒的一块砖。</p>
<p>你会遇到软件的基本元素——如算法、数据结构和设计模式。这些是软件的 ABC，深入掌握它们会使你成为一个更熟练和多才多艺的工程师。</p>
<p>当你从零开始构建时，你既是建筑师又是建造者。你可以决定每一个细节，将项目定制以适应你的兴趣和需求。</p>
<p>这就像烹饪一顿饭，你选择每一种食材来适合你的口味，使整个过程非常个人化和令人满意。</p>
<p>从零开始意味着你会经历创建软件的每一个阶段——从最初的想法草图到让它运行并向世界展示。</p>
<p>这种完整的旅程就像从头到尾阅读一本书，给你一个软件如何诞生的全貌。</p>
<p>从零开始构建通常意味着深入探索你正在使用的技术。想象一下潜入海洋中去发现下面的是什么——这就是你对每项技术的做法，理解其秘密和微妙之处。</p>
<p>在构建过程中，你会面对各种难题和挑战。你解决的每个问题都会磨练你的思维，不仅在编码方面，还在找到聪明和优雅的解决方案方面。</p>
<p>从一个简单的想法变成一个工作的程序，这种过程会带来一种特殊的自豪感和自信心。</p>
<p>这就像爬山——每一步，你都会感到更强壮和更有能力。</p>
<p>你在从零开始构建软件时克服的障碍类似于你在职业生涯中将面临的障碍。</p>
<p>无论是修复意外错误、添加复杂功能，还是管理你的时间——这些经历就像是软件工程现实世界舞台的彩排。</p>
<p>从零开始的项目是你作为软件工程师旅程的基石。这是耐心、毅力和创造力的练习。</p>
<p>记住，这不仅仅是你构建的软件。这是关于你磨练的技能，获得的知识和培养的自信。</p>
<p>每个项目都是从一个程序员到一个真正的技术艺术家的过程中的一步。所以，从一个空白文件和一个灵感的火花开始，让创造的魔力展现出来。</p>
<h2 id="">构建已经存在的东西</h2>
<p>在软件开发的激动人心的旅程中，开始一个新项目通常感觉像打开一个充满无限可能的宝箱。</p>
<p>虽然很诱人去创造一些独特而复杂的东西，但学习的路径往往需要一种更简单、更熟悉的方法。</p>
<p>现在，我们将探讨并非每个项目都必须是突破性的。有时，最好的学习来自于简单和熟悉。</p>
<p>想象一下从一个空白画布开始。你不立即绘制复杂的杰作，而是先练习简单的笔触和熟悉的图案。这是软件开发中学习的本质。</p>
<p>通过保持项目的简单性和可管理性，你可以避免陷入过于复杂的陷阱，从而专注于编码和解决问题的基本要素。</p>
<p>将现有的开源项目想象成一个图书馆，里面有你可以学习的书籍。这些项目由其他人创建并在 GitHub 等平台上共享，就像向你提供有价值的课程的指南。</p>
<p>它们是一个起点，向你展示事物是如何构建的，并鼓励你进一步探索。</p>
<p>把自己想象成一个学徒画家，通过复制大师的作品来学习。同样，在软件开发中，<a href="https://www.freecodecamp.org/news/javascript-game-tutorial-stick-hero-with-html-canvas/">克隆一个现有项目</a>是一种<a href="https://www.freecodecamp.org/news/learn-how-to-create-an-instagram-clone-using-react/">实践学习编码和解决问题</a>的方式。</p>
<p>在重新创建项目后，将你的工作与原始项目进行比较。这种比较就像一面镜子，反映出你的优势和需要改进的地方。</p>
<p>想想你每天使用的应用程序或网站。试着自己构建一个版本？这种方法使学习变得有趣和相关。</p>
<p>处理你熟悉的东西可以让你保持投入，并帮助你更深入地了解项目的复杂性。</p>
<p>在你的学习旅程中，专注于那些挑战和提高你技能的项目，而不是试图发明一些全新的东西。这就像在音乐中练习音阶——它们可能不华丽，但对成长至关重要。</p>
<p>优先考虑学习和技能发展，而不是追求突破性的想法。在你开始新的软件项目时，记住你的主要目标是作为开发人员成长。这不仅仅是构建一些新颖的东西——而是关于建立你的能力和信心。</p>
<p>通过复制现有项目并专注于学习过程，你将每个项目变成你旅程中的一个宝贵步骤。</p>
<p>这种方法不仅丰富了你的理解，也为你未来成为一名熟练的软件工程师奠定了坚实的基础。</p>
<p>所以，拿起你的工具，开始构建——不仅仅是软件，而是通向开发艺术的道路。</p>
<h1 id="">超越基础</h1>
<h2 id="">培养热爱学习的习惯</h2>
<p>软件开发是当今需求最大的职业之一。</p>
<p>不断有新的职位空缺，吸引了年轻人和来自广泛职业领域的已经就业的人。</p>
<p>他们知道，作为软件工程师可以获得非常好的薪水，因此他们带着巨大的野心开始职业生涯。</p>
<p>即使你在软件开发领域找到一份工作，如果你真的想变得优秀，热爱学习和编程是有帮助的。</p>
<p>这是少数几个你必须不断学习新事物的职业之一。你不仅需要了解现有的概念。你还必须适应不断涌入的新技术。</p>
<p>你必须适应市场的变化，学习当前被认为有价值的新事物。简而言之，你将不得不持续学习很多。</p>
<p>为了让你的大脑不断参与学习，你必须保持好奇心并保持谦逊。</p>
<p>经常有程序员基于他们的现有知识被雇佣，开始认为他们不再需要学习新东西。但如果你想成为优秀的软件工程师，保持好奇心并热爱学习是必要的，因为学习的需求永不停息。</p>
<p>1915 年 11 月，在写下他所称的“我生命中最美的作品之一”仅两页后，爱因斯坦给他 11 岁的儿子汉斯·阿尔伯特写了一封信。</p>
<p>他赞扬儿子的学习努力，说：“那是学习最多的方法……当你做某事时如此享受，以至于你没有注意到时间的流逝。”</p>
<p>“好奇心有其存在的理由，”爱因斯坦解释道。“当人们思考永恒、生命和现实奇妙结构的奥秘时，无法不感到敬畏。”</p>
<p>对框架的工作原理和结构产生好奇心。当你彻底学习某件事时，你会对其机制和功能有一个清晰的认识。</p>
<p>例如，不要仅仅接受 scikit-learn 是一个很棒的机器学习框架——学习它是如何工作的，背后的机制。并考虑对其做出贡献和改进，因为它是开源的。</p>
<p>另外，尽量不要过分关注金钱。当然，我们都需要钱来支付账单和为自己和家人买食物。这些是基本需求，我们需要满足它们——所以钱很重要。但试着培养对学习和开发的热情。这样，经济回报会更加令人满意。</p>
<p>试着培养对编程的热爱，并感激你有机会通过你编写的代码积极影响数百万人的生活。</p>
<p>爱因斯坦认为，“爱是比责任感更好的老师。”</p>
<p>我们作为软件工程师可以从中学到的是，不仅仅是为了高薪工作，而是因为我们热爱学习和我们的工作。如果我们能够培养一种内在的好奇心和动力，让我们在下班后或周末继续投入，那就更好了。</p>
<h2 id="">看大局</h2>
<p>在快节奏和令人兴奋的软件工程世界中，理解成为软件工程师不仅仅是写代码是至关重要的。</p>
<p>想象一下你不仅是一个建造者，也是一个建筑师和一个远见者。你的角色就像是一个大团队中的关键成员，你的想法和工作帮助团队获胜。</p>
<h3 id="">理解你的影响</h3>
<p>作为软件工程师，你可能花很多时间处理特定的编码任务——像是一块一块地解决难题。</p>
<p>但是，重要的是要记住，你实际上是在帮助完成一个更大的拼图。</p>
<p>假设你的公司像一艘大船，你不仅仅是在修理船的部件——你是在帮助它到达目的地。</p>
<p>想象一下你正在为一个当地面包店制作一个应用程序。除了关注按钮的工作，还要考虑你的应用程序如何帮助面包店吸引更多客户并让他们的生活更轻松。</p>
<h3 id="">看整体，不仅仅是部分</h3>
<p>随着你在职业生涯中的成长，你将不仅看到你写的代码行，还会看到整个项目，就像看整个森林而不是一棵树。</p>
<p>这意味着你将开始理解你的工作如何影响其他一切，并能够做出有助于整个业务的决策。</p>
<p>想想你手机上的拼图游戏。如果你只专注于一个小部分，你可能会错过一个能解决更多拼图的更好解决方案。</p>
<h3 id="">从编码到贡献</h3>
<p>当你开始专注于最重要的任务时，你不仅仅是一个写代码的人。你变成了一个解决大问题的人。</p>
<p>这就像从游戏中的一个玩家转变为帮助计划游戏策略的人。</p>
<p>想象你的公司像一个花园。一开始，你可能是在种植单个花朵（写代码）。但后来，你开始规划种植树木的位置以及如何使花园更美丽（战略性思考）。</p>
<h3 id="">不仅是程序员</h3>
<p>通过使你的工作与业务的实际需求保持一致，你成为团队中的关键成员。你的工作开始产生重大影响，你成为每个人依赖的人。</p>
<p>这就像在体育团队中不仅得分还帮助球队赢得冠军的明星球员。</p>
<p>如果你在一个网站上工作，不仅仅是让它看起来好。想想它如何运作，如何吸引更多的访问者，以及如何帮助业务增长。</p>
<p>成为软件工程师是一段惊人的旅程。这不仅仅是写代码，而是利用你的技能帮助业务及其客户。</p>
<p>当你开始以这种更大的方式看待你的角色时，你不仅作为程序员成长，而且作为团队的关键成员成长。</p>
<p>这种方法将帮助你在令人兴奋的软件工程世界中在个人和专业方面发展。</p>
<p>记住，你不仅是在构建软件——你在构建成功故事。</p>
<h2 id="">拥抱终身学习</h2>
<p>将软件工程领域视为一场不断进行的马拉松，而不是一次性的比赛，在每个转弯处都有新的激动人心的路径等待探索。</p>
<p>你的正规教育，无论是获得大学学位，参加培训营还是自学编程——这只是起点。</p>
<p>前方是一段持续学习和成长的激动人心的冒险。</p>
<p>将自己想象成技术世界中的侦探。每个新挑战都是等待解决的谜题。</p>
<p>一开始，这些谜题可能看起来令人生畏，但随着你学到更多，你会在拼凑解决方案中找到乐趣。这段旅程增强了你的自信，并将复杂的问题变成令人兴奋的探索。</p>
<p>在快速变化的技术领域，今天的热门可能明天就被遗忘。因此，虽然跟上最新趋势并了解最新动向很重要，但不要忘记学习基础知识并掌握主流技术。</p>
<p>因此，虽然你会想学习新的编程语言和框架，并熟悉最新的软件，但要实际地选择你关注的内容。</p>
<p>随着你学习和成长，作为软件工程师的价值将飞速上升。</p>
<p>这不仅仅是为了赚取更高的薪水——还包括参与更激动人心和具有挑战性的项目。</p>
<p>就像一位备受追捧的艺术家一样，你最新的技能和知识可以帮助你在技术世界中成为热门人物。</p>
<p>想象你学到的每个新技能都是一把钥匙。你拥有的钥匙越多，你能打开的门就越多。这可能导致更好的工作机会，参与开创性的项目，甚至领导团队。</p>
<p>你的知识和经验就像一张地图，引导你走向一个充实和充满活力的职业。</p>
<h2 id="">祝你好运！</h2>
<p>感谢你阅读这本手册！希望你现在感觉更有准备进入科技世界，提升你的技能，并朝着你的第一个——或下一个——开发者工作努力。</p>
<h3 id="pdf">获取本书的 PDF 版本</h3>
<p>你可以通过<a href="https://fatosmorina.gumroad.com/l/coding-for-everyone">这里</a>下载 PDF 版本阅读这本书。</p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
