A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

преди 4 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>To Rewrite or Not, That is The Question (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="http://blog.aelogica.com/development/rewrite-not-question/">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. To Rewrite or Not, That is The Question (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="http://blog.aelogica.com/development/rewrite-not-question/">Source originale du contenu</a></h3>
  445. <p><a href="http://blog.aelogica.com/wp-content/uploads/2015/02/To-Rewrite-or-Not-That-is-The-Question.jpg"><img class=" size-medium wp-image-3167 aligncenter" src="http://blog.aelogica.com/wp-content/uploads/2015/02/To-Rewrite-or-Not-That-is-The-Question-250x314.jpg" alt="To Rewrite or Not, That is The Question"/></a></p>
  446. <h2>A Million Dollar Problem</h2>
  447. <p>You have a successful software product or web application that took years to produce and debug. Now you want to pursue new opportunities and make major changes, perhaps refresh the user interface to keep up with changing trends and competition but your development velocity has slowed to a crawl.</p>
  448. <p>You hear gripes from your developers about the state of your code. Changes are difficult and error-prone. Your developers have begun to advocate a for a Big Rewrite or perhaps soft-pedalling the issue, a mere “overhaul.”</p>
  449. <p>This is a common scenario for growing businesses and it presents a very tricky and potentially expensive problem. Sometimes it even presents a lurking existential threat to the business.</p>
  450. <p>At ÆLOGICA and in my prior freelance work, I have assisted or led customers to re-write or “re-skin” as well as simply maintain, enhance and refactor large existing Ruby on Rails web applications. We have tried different approaches and I have a number of useful observations to share about the process.</p>
  451. <p>As David Heinemeier Hansson, creator of Ruby on Rails and founder of Basecamp, recently advocated in his post, <a href="https://signalvnoise.com/posts/3856-the-big-rewrite-revisited?15#comments">The Big Rewrite, revisited</a>, sometimes the right answer is to do the dreaded Big Rewrite, but with the caveat that how you treat users in the process can make all the difference.</p>
  452. <p>What makes people want to abandon a working system and start fresh? What are the options? Is there a less risky approach?</p>
  453. <p>Naturally every case requires a close examination of the business objectives and strategic direction, as well the code base, financial resources, team size and the history of development effort and velocity.</p>
  454. <h2>Calculate the Maintenance Burden</h2>
  455. <p>Maintenance of a large code base or system will eventually grow to consume a majority of a development team’s bandwidth — especially if team size is kept constant. This leaves a shrinking portion to devote to new features and changes to advance the objectives of the business. As this situation persists and worsens, management becomes frustrated with progress and team morale suffers.</p>
  456. <p>Retention of key talent often presents a substantial unexpected risk to the business. Competitors may pull ahead while you are stuck trying to backfill departures and onboard new team members. Something must be done, but what? Product managers, engineering managers and executives are right to tread cautiously.</p>
  457. <p>I use a rule of thumb that for every X developer-years of new feature development, 20% of X will be spent in each subsequent year on maintenance of that previous effort. Everything you do imposes an ongoing cost stretching to the end of system life. That is reality, regardless of whether you employ top talent or follow best-practices.</p>
  458. <p>Let’s look at what this looks like over 5 years. For purposes of simplicity, we will assume we do no “maintenance” in the first year.</p>
  459. <p><a href="http://blog.aelogica.com/wp-content/uploads/2015/02/To-Rewrite-or-Not-Chart.png"><img class=" size-full wp-image-3166 aligncenter" src="http://blog.aelogica.com/wp-content/uploads/2015/02/To-Rewrite-or-Not-Chart.png" alt="To Rewrite or Not Chart"/></a></p>
  460. <p>Here we assume a constant team size of say 4 developers for the entire 5 years. By Year 4, our productivity from the point of view of the business has halved. By Year 5, we are spending the majority of our time just keeping the thing running — treading water. This is right about the time the business may wish to make a strategic shift, branch out into new markets or exploit new opportunities.</p>
  461. <p>Often team size grows and shrinks over the course of the system lifetime. Perhaps management engages contractors or an outside firm or agency to meet targets early on. If in Year 2 and 3, additional developers were added to increase velocity, and several developers departed or the engagement ended by Years 4 and 5, 90% or more of the team’s bandwidth in Year 5 could easily be devoted to Maintenance. Forward progress would be almost nil. Turnover and other factors could further limit productivity.</p>
  462. <p>Of course your mileage may vary. Your number might not be exactly 20%. Very talented and senior developers can avoid many of the pitfalls that bring about this painful state too early. Less-skilled developers or careless outsourcing to less competent agencies can accelerate the problem such that by Year 2 or 3, you are in deep trouble already. In either case, the growing maintenance burden is inevitable and so will be the eventual call to do a Big Rewrite.</p>
  463. <p>If you find yourself in this situation, and you have managed to retain ambitious and talented-enough developers, especially if they are not the ones you started with, they will likely want to throw out the whole thing and start over.</p>
  464. <p>When Product comes along and asks for a major overhaul or a substantial new feature set, a new UI or all three, the developers will often use this as an opportunity to push for the Big Rewrite. Occasionally they may make a compelling enough argument. Often the real argument is that they will leave if the company does not pursue a rewrite. Now it may feel like you are being held for ransom by your own team!</p>
  465. <p>This is often a million dollar or multi-million dollar problem. The wrong move can sink your company and put you out of business or merely close off precious opportunities for substantial growth.</p>
  466. <p>Let’s pause there between Scylla and Charybdis for a moment.</p>
  467. <h2>Why Do We Want to Do This?</h2>
  468. <p>There can be good reasons. Are they good enough?</p>
  469. <p>After five or more years, perhaps you have a much keener understanding of your customer base and product than you did at the outset. If senior technical people agree that a different architecture would much better serve your needs, it can make sense. Proceed with extreme caution. Perhaps it would be better to start a new product along side the existing one to address the new opportunities. As DHH suggests in the article linked above, you might want to plan to run your new product version in parallel with the old one indefinitely and not force customers to upgrade.</p>
  470. <p>Perhaps your developers argue that the state of the code is a mess and it takes too long to make changes. When your team makes changes, they introduce too many bugs. If this is the substance of the argument for a rewrite but at the same time no major architectural change is proposed, rewriting may not be the best option. Your team may simply be in over their head.</p>
  471. <p>You might want to call in a senior consultant to evaluate refactoring the most painful parts of the system and to chart a path to sustainability. Even if expensive, this can be much cheaper than a rewrite and lower-risk.</p>
  472. <p>Another common argument, although rarely stated this way, is that some new programming language or stack is the new hotness and would better serve your needs than your current obsolete stuff. The not-so-hidden agenda here is that your team wants to pad their resume with highly marketable skills and look for higher-paying jobs. They are not wrong to want this. Why shouldn’t they? You may even need to accommodate them. Be careful though. If the project goes poorly or you mismanage, you could lose half your team before you go live. The developers will all be learning on the job, doing their first big system in the new language or stack and will make neophyte mistakes as they go.</p>
  473. <p>It is possible to succeed at switching languages and frameworks. It may even be justified if your current system really is so old and obsolete that you cannot find people with the skills to work on it. Obtain outside advice on the proposed solution and consider the needs of your staff for professional growth as well as your ability to attract and retain developers experienced in the new platform. Try to hire a couple developers who already have experience in the new platform who can help prevent your team from making mistakes as they learn. If you are unable to hire experienced developers in the new technology, consider it a sign that you won’t be able to hire them in the future and decline the platform switch or look for another better option.</p>
  474. <h2>How Do You Staff for a Rewrite?</h2>
  475. <p>In my experience, a total system rewrite for a large web application that has more than a couple years of active, full-time development and production use can take anywhere from 6 months on the very lowest end to more than 2 years. The more work involved, the bigger the team required. Two to four developers is generally adequate, with perhaps a maximum of six. Larger teams introduce the need for greater management and planning and may actually take longer to ship. Six experienced developers may cost almost $1 Million per year in the United States. Two developers for six months will cost about $150-200k depending on whether they are employees or contractors, etc. Any way you cut it, this is not going to be cheap.</p>
  476. <p>If you have a team that is talented enough and highly motivated to do a rewrite, and they have convinced you that it is the right thing to do for the long term interest of the business, you will still have the problem of how to maintain and enhance the existing application while they run off for potentially a couple YEARS to complete said big rewrite. Keep in mind, it always takes longer than you expect and you will not likely achieve feature parity until well after launch. Everyone internally will want in on the project. Few will be happy to maintain the old system while everyone else is having fun on the new system.</p>
  477. <p>I view maintenance, enhancement and the responsible, long-term-care of existing systems to require a high degree of professionalism and skill. Often it even requires higher skill and discipline than writing new code. This type of work is for mature professional developers. If you are proceeding with a rewrite, you need your most experienced developers on your new system to make sure it really will be as good as they claim. You may have difficulty hiring developers with the skills to maintain your existing application as this type of work is often viewed as less desirable.</p>
  478. <p>Consider augmenting your maintenance team with outside or offshore developers.</p>
  479. <p>At ÆLOGICA, we specialize in providing teams of skilled Ruby on Rails developers for long term engagements. We provide quality developer bandwidth like a utility for clients who need to augment their internal capabilities.</p>
  480. <p>Whether you are exploring a rewrite, overhaul, re-skin or other major effort, if you need more talent and capability than you can source locally, or if you just want some outside advice on how to address these concerns, please reach out to me: steve@aelogica.com</p>
  481. </article>
  482. </section>
  483. <nav id="jumpto">
  484. <p>
  485. <a href="/david/blog/">Accueil du blog</a> |
  486. <a href="http://blog.aelogica.com/development/rewrite-not-question/">Source originale</a> |
  487. <a href="/david/stream/2019/">Accueil du flux</a>
  488. </p>
  489. </nav>
  490. <footer>
  491. <div>
  492. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  493. <p>
  494. Bonjour/Hi!
  495. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  496. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  497. </p>
  498. <p>
  499. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  500. </p>
  501. <p>
  502. Voici quelques articles choisis :
  503. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  504. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  505. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  506. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  507. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  508. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  509. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  510. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  511. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  512. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  513. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  514. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  515. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  516. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  517. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  518. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  519. </p>
  520. <p>
  521. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  522. </p>
  523. <p>
  524. Je ne traque pas ta navigation mais mon
  525. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  526. conserve des logs d’accès.
  527. </p>
  528. </div>
  529. </footer>
  530. <script type="text/javascript">
  531. ;(_ => {
  532. const jumper = document.getElementById('jumper')
  533. jumper.addEventListener('click', e => {
  534. e.preventDefault()
  535. const anchor = e.target.getAttribute('href')
  536. const targetEl = document.getElementById(anchor.substring(1))
  537. targetEl.scrollIntoView({behavior: 'smooth'})
  538. })
  539. })()
  540. </script>