精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

程序員必知之前端演進史

移動開發
維基百科是這樣說的:前端Front-end和后端back-end是描述進程開始和結束的通用詞匯。前端作用于采集輸入信息,后端進行處理。計算機程序的界面樣式,視覺呈現屬于前端。這種說法給人一種很模糊的感覺,但是他說得又很對,它負責視覺展示。在MVC結構或者MVP中,負責視覺顯示的部分只有View層,而今天大多數所謂的View層已經超越了View層。前端是一個很神奇的概念,但是而今的前端已經發生了很大的變化。

細細整理了過去接觸過的那些前端技術,發現前端演進是段特別有意思的歷史。人們總是在過去就做出未來需要的框架,而現在流行的是過去的過去發明過的。如,響應式設計不得不提到的一個缺點是:他只是將原本在模板層做的事,放到了樣式(CSS)層來完成。

復雜度同力一樣不會消失,也不會憑空產生,它總是從一個物體轉移到另一個物體或一種形式轉為另一種形式。

如果六、七年前的移動網絡速度和今天一樣快,那么直接上的技術就是響應式設計,APP、SPA就不會流行得這么快。盡管我們可以預見未來這些領域會變得更好,但是更需要的是改變現狀。改變現狀的同時也需要預見未來的需求。

什么是前端?

維基百科是這樣說的:前端Front-end和后端back-end是描述進程開始和結束的通用詞匯。前端作用于采集輸入信息,后端進行處理。計算機程序的界面樣式,視覺呈現屬于前端。

這種說法給人一種很模糊的感覺,但是他說得又很對,它負責視覺展示。在MVC結構或者MVP中,負責視覺顯示的部分只有View層,而今天大多數所謂的View層已經超越了View層。前端是一個很神奇的概念,但是而今的前端已經發生了很大的變化。

你引入了Backbone、Angluar,你的架構變成了MVP、MVVM。盡管發生了一些架構上的變化,但是項目的開發并沒有因此而發生變化。這其中涉及到了一些職責的問題,如果某一個層級中有太多的職責,那么它是不是加重了一些人的負擔?

前端演進史

過去一直想整理一篇文章來說說前端發展的歷史,但是想著這些歷史已經被人們所熟知。后來發現并非如此,大抵是幸存者偏見——關注到的都知道這些歷史。

數據-模板-樣式混合

在有限的前端經驗里,我還是經歷了那段用Table來作樣式的年代。大學期間曾經有償幫一些公司或者個人開發、維護一些CMS,而Table是當時幫某個網站更新樣式接觸到的——ASP.Net(maybe)。當時,我們啟動這個CMS用的是一個名為aspweb.exe的程序。于是,在我的移動硬盤里找到了下面的代碼。

  1. <TABLE cellSpacing=0 cellPadding=0 width=910 align=center border=0
  2.   <TBODY> 
  3.   <TR> 
  4.     <TD vAlign=top width=188><TABLE cellSpacing=0 cellPadding=0 width=184 align=center border=0
  5.         <TBODY> 
  6.         <TR> 
  7.           <TD>[站外圖片上傳中……(9)]</TD></TR> 
  8.         <TR> 
  9.           <TD> 
  10.             <TABLE cellSpacing=0 cellPadding=0 width=184 align=center  
  11.             background=Images/xxx.gif border=0

雖然,我也已經在HEAD里找到了現代的雛形——DIV + CSS,然而這仍然是一個Table的年代。

  1. <LINK href="img/xxx.css" type=text/css rel=stylesheet> 

人們一直在說前端很難,問題是你學過么???

人們一直在說前端很難,問題是你學過么???

人們一直在說前端很難,問題是你學過么???

也許,你也一直在說CSS不好寫,但是CSS真的不好寫么?人們總在說JS很難用,但是你學過么?只在需要的時候才去學,那肯定很難。你不曾花時間去學習一門語言,但是卻能直接寫出可以work的代碼,說明他們容易上手。如果你看過一些有經驗的Ruby、Scala、Emacs Lisp開發者寫出來的代碼,我想會得到相同的結論。有一些語言可以讓寫程序的人Happy,但是看的人可能就不Happy了。做事的方法不止一種,但是不是所有的人都要用那種方法去做。

過去的那些程序員都是真正的全棧程序員,這些程序員不僅僅做了前端的活,還做了數據庫的工作。

  1. Set rs = Server.CreateObject("ADODB.Recordset"
  2. sql = "select id,title,username,email,qq,adddate,content,Re_content,home,face,sex from Fl_Book where ispassed=1 order by id desc" 
  3. rs.open sql, Conn, 11 
  4. fl.SqlQueryNum = fl.SqlQueryNum + 1 

在這個ASP文件里,它從數據庫里查找出了數據,然后Render出HTML。如果可以看到歷史版本,那么我想我會看到有一個作者將style=""的代碼一個個放到css文件中。

在這里的代碼里也免不了有動態生成JavaScript代碼的方法:

  1. show_other = "<SCRIPT language=javascript>" 
  2. show_other = show_other & "function checkform()" 
  3. show_other = show_other & "{" 
  4. show_other = show_other & "if (document.add.title.value=='')" 
  5. show_other = show_other & "{" 

請盡情嘲笑,然后再看一段代碼:

  1. import React from "react"
  2. import { getData } from "../../common/request"
  3. import styles from "./style.css"
  4.  
  5.  
  6. export default class HomePage extends React.Component { 
  7.   componentWillMount() { 
  8.     console.log("[HomePage] will mount with server response: "this.props.data.home); 
  9.   } 
  10.  
  11.   render() { 
  12.     let { title } = this.props.data.home; 
  13.  
  14.     return ( 
  15.       <div className={styles.content}> 
  16.         <h1>{title}</h1> 
  17.         <p className={styles.welcomeText}>Thanks for joining!</p> 
  18.       </div> 
  19.     ); 
  20.   } 
  21.  
  22.   static fetchData = function(params) { 
  23.     return getData("/home"); 
  24.   } 

10年前和10年后的代碼,似乎沒有太多的變化。有所不同的是數據層已經被獨立出去了,如果你的component也混合了數據層,即直接查詢數據庫而不是調用數據層接口,那么你就需要好好思考下這個問題。你只是在追隨潮流,還是在改變。用一個View層更換一個View層,用一個Router換一個Router的意義在哪?

Model-View-Controller

人們在不斷地反思這其中復雜的過程,整理了一些好的架構模式,其中不得不提到的是我司Martin Folwer的《企業應用架構模式》。該書中文譯版出版的時候是2004年,那時對于系統的分層是

層次 職責
表現層 提供服務、顯示信息、用戶請求、HTTP請求和命令行調用。
領域層 邏輯處理,系統中真正的核心。
數據層 與數據庫、消息系統、事物管理器和其他軟件包通訊。

化身于當時***的Spring,就是MVC。人們有了iBatis這樣的數據持久層框架,即ORM,對象關系映射。于是,你的package就會有這樣的幾個文件夾:

  1. |____mappers 
  2. |____model 
  3. |____service 
  4. |____utils 
  5. |____controller 

在mappers這一層,我們所做的莫過于如下所示的數據庫相關查詢:

  1. @Insert
  2.         "INSERT INTO users(username, password, enabled) " + 
  3.                 "VALUES (#{userName}, #{passwordHash}, #{enabled})" 
  4. @Options(keyProperty = "id", keyColumn = "id", useGeneratedKeys = true
  5. void insert(User user); 

model文件夾和mappers文件夾都是數據層的一部分,只是兩者間的職責不同,如:

  1. public String getUserName() { 
  2.     return userName; 
  3.  
  4. public void setUserName(String userName) { 
  5.     this.userName = userName; 

而他們***都需要在Controller,又或者稱為ModelAndView中處理:

  1. @RequestMapping(value = {"/disableUser"}, method = RequestMethod.POST) 
  2. public ModelAndView processUserDisable(HttpServletRequest request, ModelMap model) { 
  3.     String userName = request.getParameter("userName"); 
  4.     User user = userService.getByUsername(userName); 
  5.     userService.disable(user); 
  6.     Map<String,User> map = new HashMap<String,User>(); 
  7.     Map <User,String> usersWithRoles= userService.getAllUsersWithRole(); 
  8.     model.put("usersWithRoles",usersWithRoles); 
  9.     return new ModelAndView("redirect:users",map); 

在多數時候,Controller不應該直接與數據層的一部分,而將業務邏輯放在Controller層又是一種錯誤,這時就有了Service層,如下圖:

Service MVC

然而對于Domain相關的Service應該放在哪一層,總會有不同的意見:

MVC Player

MS MVC

Domain(業務)是一個相當復雜的層級,這里是業務的核心。一個合理的Controller只應該做自己應該做的事,它不應該處理業務相關的代碼:

  1. if (isNewnameEmpty == false && newuser == null){ 
  2.     user.setUserName(newUsername); 
  3.     List<Post> myPosts = postService.findMainPostByAuthorNameSortedByCreateTime(principal.getName()); 
  4.  
  5.     for (int k = 0;k < myPosts.size();k++){ 
  6.         Post post = myPosts.get(k); 
  7.         post.setAuthorName(newUsername); 
  8.         postService.save(post); 
  9.     } 
  10.     userService.update(user); 
  11.     Authentication oldAuthentication = SecurityContextHolder.getContext().getAuthentication(); 
  12.     Authentication authentication = null
  13.     if(oldAuthentication == null){ 
  14.         authentication = new UsernamePasswordAuthenticationToken(newUsername,user.getPasswordHash()); 
  15.     }else
  16.         authentication = new UsernamePasswordAuthenticationToken(newUsername,user.getPasswordHash(),oldAuthentication.getAuthorities()); 
  17.     } 
  18.     SecurityContextHolder.getContext().setAuthentication(authentication); 
  19.     map.clear(); 
  20.     map.put("user",user); 
  21.     model.addAttribute("myPosts", myPosts); 
  22.     model.addAttribute("namesuccess""User Profile updated successfully"); 
  23.     return new ModelAndView("user/profile", map); 

我們在Controller層應該做的事是:

  1. 處理請求的參數
  2. 渲染和重定向
  3. 選擇Model和Service
  4. 處理Session和Cookies

業務是善變的,昨天我們可能還在和對手競爭誰先推出新功能,但是今天可能已經合并了。我們很難預見業務變化,但是我們應該能預見Controller是不容易變化的。在一些設計里面,這種模式就是Command模式。

View層是一直在變化的層級,人們的品味一直在更新,有時甚至可能因為競爭對手而產生變化。在已經取得一定市場的情況下,Model-Service-Controller通常都不太會變動,甚至不敢變動。企業意識到創新的兩面性,要么帶來死亡,要么占領更大的市場。但是對手通常都比你想象中的更聰明一些,所以這時開創新的業務是一個更好的選擇。

高速發展期的企業和發展初期的企業相比,更需要前端開發人員。在用戶基數不夠、業務待定的情形中,View只要可用并美觀就行了,這時可能就會有大量的業務代碼放在View層:

  1. <c:choose> 
  2.     <c:when test="${ hasError }"
  3.     <p class="prompt-error"
  4.         ${errors.username} ${errors.password} 
  5.     </p> 
  6.     </c:when> 
  7.     <c:otherwise> 
  8.     <p class="prompt"
  9.         Woohoo, User <span class="username">${user.userName}</span> has been created successfully! 
  10.     </p> 
  11.     </c:otherwise> 
  12. </c:choose> 

不同的情形下,人們都會對此有所爭議,但只要符合當前的業務便是***的選擇。作為一個前端開發人員,在過去我需要修改JSP、PHP文件,這期間我需要去了解這些Template:

  1. {foreach $lists as $v} 
  2. <li itemprop="breadcrumb"><span{if(newest($v['addtime'],24))} style="color:red"{/if}>[{fun date('Y-m-d',$v['addtime'])}]</span><a href="{$v['url']}" style="{$v['style']}" target="_blank">{$v['title']}</a></li> 
  3. {/foreach} 

有時像Django這一類,自稱為Model-Template-View的框架,更容易讓人理解其意圖:

  1. {% for blog_post in blog_posts.object_list %} 
  2. {% block blog_post_list_post_title %} 
  3. <section class="section--center mdl-grid mdl-grid--no-spacing mdl-shadow--2dp mdl-cell--11-col blog-list"
  4. {% editable blog_post.title %} 
  5. <div class="mdl-card__title mdl-card--border mdl-card--expand"
  6.     <h2 class="mdl-card__title-text"
  7.         <a href="{{ blog_post.get_absolute_url }}"  itemprop="headline">{{ blog_post.title }} › </a> 
  8.     </h2> 
  9. </div> 
  10. {% endeditable %} 
  11. {% endblock %} 

作為一個前端人員,我們真正在接觸的是View層和Template層,但是MVC并沒有說明這些。

從桌面版到移動版

Wap出現了,并帶來了更多的挑戰。隨后,分辨率從1024x768變成了176×208,開發人員不得不面臨這些挑戰。當時所需要做的僅僅是修改View層,而View層隨著iPhone的出現又發生了變化。

WAP 網站

這是一個短暫的歷史,PO還需要為手機用戶制作一個怎樣的網站?于是他們把桌面版的網站搬了過去變成了移動版。由于網絡的原因,每次都需要重新加載頁面,這帶來了不佳的用戶體驗。

幸運的是,人們很快意識到了這個問題,于是就有了SPA。如果當時的移動網絡速度可以更快的話,我想很多SPA框架就不存在了。

先說說jQuery Mobile,在那之前,先讓我們來看看兩個不同版本的代碼,下面是一個手機版本的blog詳情頁:

  1. <ul data-role="listview" data-inset="true" data-splittheme="a"
  2.     {% for blog_post in blog_posts.object_list %} 
  3.         <li> 
  4.         {% editable blog_post.title blog_post.publish_date %} 
  5.         <h2 class="blog-post-title"><a href="{% url "blog_post_detail" blog_post.slug %}">{{ blog_post.title }}</a></h2> 
  6.         <em class="since">{% blocktrans with sometime=blog_post.publish_date|timesince %}{{ sometime }} ago{% endblocktrans %}</em> 
  7.         {% endeditable %} 
  8.         </li> 
  9.     {% endfor %} 
  10. </ul> 

而下面是桌面版本的片段:

  1. {% for blog_post in blog_posts.object_list %} 
  2. {% block blog_post_list_post_title %} 
  3. {% editable blog_post.title %} 
  4. <h2> 
  5.     <a href="{{ blog_post.get_absolute_url }}">{{ blog_post.title }}</a> 
  6. </h2> 
  7. {% endeditable %} 
  8. {% endblock %} 
  9. {% block blog_post_list_post_metainfo %} 
  10. {% editable blog_post.publish_date %} 
  11. <h6 class="post-meta"
  12.     {% trans "Posted by" %}: 
  13.     {% with blog_post.user as author %} 
  14.     <a href="{% url "blog_post_list_author" author %}">{{ author.get_full_name|default:author.username }}</a> 
  15.     {% endwith %} 
  16.     {% with blog_post.categories.all as categories %} 
  17.     {% if categories %} 
  18.     {% trans "in" %} 
  19.     {% for category in categories %} 
  20.     <a href="{% url "blog_post_list_category" category.slug %}">{{ category }}</a>{% if not forloop.last %}, {% endif %} 
  21.     {% endfor %} 
  22.     {% endif %} 
  23.     {% endwith %} 
  24.     {% blocktrans with sometime=blog_post.publish_date|timesince %}{{ sometime }} ago{% endblocktrans %} 
  25. </h6> 
  26. {% endeditable %} 
  27. {% endblock %} 

人們所做的只是重載View層。這也是一個有效的SEO策略,上面這些代碼是我博客過去的代碼。對于桌面版和移動版都是不同的模板和不同的JS、CSS。

移動版網頁

在這一時期,桌面版和移動版的代碼可能在同一個代碼庫中。他們使用相同的代碼,調用相同的邏輯,只是View層不同了。但是,每次改動我們都要維護兩份代碼。

隨后,人們發現了一種更友好的移動版應用——APP。

APP與過渡期API

這是一個艱難的時刻,過去我們的很多API都是在原來的代碼庫中構建的,即桌面版和移動版一起。我們已經在這個代碼庫中開發了越來越多的功能,系統開發變得臃腫。如《Linux/Unix設計思想》中所說,這是一個偉大的系統,但是它臃腫而又緩慢。

我們是選擇重新開發一個結合***和第二系統的***特性的第三個系統,還是繼續臃腫下去。我想你已經有答案了。隨后我們就有了APP API,構建出了博客的APP。

應用

最開始,人們越來越喜歡用APP,因為與移動版網頁相比,其響應速度更快,而且更流暢。對于服務器來說,也是一件好事,因為請求變少了。

但是并非所有的人都會下載APP——有時只想看看上面有沒有需要的東西。對于剛需不強的應用,人們并不會下載,只會訪問網站。

有了APP API之后,我們可以向網頁提供API,我們就開始設想要有一個好好的移動版。

過渡期SPA

Backbone誕生于2010年,和響應式設計出現在同一個年代里,但他們似乎在同一個時代里火了起來。如果CSS3早點流行開來,似乎就沒有Backbone啥事了。不過移動網絡還是限制了響應式的流行,只是在今天這些都有所變化。

我們用Ajax向后臺請求API,然后Mustache Render出來。因為JavaScript在模塊化上的缺陷,所以我們就用Require.JS來進行模塊化。

下面的代碼就是我在嘗試對我的博客進行SPA設計時的代碼:

  1. define([ 
  2.     'zepto'
  3.     'underscore'
  4.     'mustache'
  5.     'js/ProductsView'
  6.     'json!/configure.json'
  7.     'text!/templates/blog_details.html'
  8.     'js/renderBlog' 
  9. ],function($, _, Mustache, ProductsView, configure, blogDetailsTemplate, GetBlog){ 
  10.  
  11.     var BlogDetailsView = Backbone.View.extend ({ 
  12.         el: $("#content"), 
  13.  
  14.         initialize: function () { 
  15.             this.params = '#content'
  16.         }, 
  17.  
  18.         getBlog: function(slug) { 
  19.             var getblog = new GetBlog(this.params, configure['blogPostUrl'] + slug, blogDetailsTemplate); 
  20.             getblog.renderBlog(); 
  21.         } 
  22.     }); 
  23.  
  24.     return BlogDetailsView; 
  25. }); 

從API獲取數據,結合Template來Render出Page。但是這無法改變我們需要Client Side Render和Server Side Render的兩種Render方式,除非我們可以像淘寶一樣不需要考慮SEO——因為它不那么依靠搜索引擎帶來流量。

這時,我們還是基于類MVC模式。只是數據的獲取方式變成了Ajax,我們就犯了一個錯誤——將大量的業務邏輯放在前端。這時候我們已經不能再從View層直接訪問Model層,從安全的角度來說有點危險。

如果你的View層還可以直接訪問Model層,那么說明你的架構還是MVC模式。之前我在Github上構建一個Side Project的時候直接用View層訪問了Model層,由于Model層是一個ElasticSearch的搜索引擎,它提供了JSON API,這使得我要在View層處理數據——即業務邏輯。將上述的JSON API放入Controller,盡管會加重這一層的復雜度,但是業務邏輯就不再放置于View層。

如果你在你的View層和Model層總有一層接口,那么你采用的就是MVP模式——MVC模式的衍生(PS:為了區別別的事情,總會有人取個表意的名稱)。

一夜之前,我們又回到了過去。我們離開了JSP,將View層變成了Template與Controller。而原有的Services層并不是只承擔其原來的責任,這些Services開始向ViewModel改變。

一些團隊便將Services抽成多個Services,美其名為微服務。傳統架構下的API從下圖

API Gateway

變成了直接調用的微服務:

Micro Services

對于后臺開發者來說,這是一件大快人心的大好事,但是對于應用端/前端來說并非如此。調用的服務變多了,在應用程序端進行功能測試變得更復雜,需要Mock的API變多了。

Hybird與ViewModel

這時候遇到問題的不僅僅只在前端,而在App端,小的團隊已經無法承受開發成本。人們更多的注意力放到了Hybird應用上。Hybird應用解決了一些小團隊在開發初期遇到的問題,這部分應用便交給了前端開發者。

前端開發人員先熟悉了單純的JS + CSS + HTML,又熟悉了Router + PageView + API的結構,現在他們又需要做手機APP。這時候只好用熟悉的jQuer Mobile + Cordova。

隨后,人們先從Cordova + jQuery Mobile,變成了Cordova + Angular的 Ionic。在那之前,一些團隊可能已經用Angular代換了Backbone。他們需要更好的交互,需要data binding。

接著,我們可以直接將我們的Angular代碼從前端移到APP,比如下面這種博客APP的代碼:

  1. .controller('BlogCtrl', function ($scope, Blog) { 
  2.    $scope.blogs = null
  3.    $scope.blogOffset = 0
  4.    // 
  5.    $scope.doRefresh = function () { 
  6.      Blog.async('https://www.phodal.com/api/v1/app/?format=json').then(function (results) { 
  7.        $scope.blogs = results.objects; 
  8.      }); 
  9.      $scope.$broadcast('scroll.refreshComplete'); 
  10.      $scope.$apply() 
  11.    }; 
  12.  
  13.    Blog.async('https://www.phodal.com/api/v1/app/?format=json').then(function (results) { 
  14.      $scope.blogs = results.objects; 
  15.    }); 
  16.  
  17.    $scope.loadMore = function() { 
  18.      $scope.blogOffset = $scope.blogOffset + 1
  19.      Blog.async('https://www.phodal.com/api/v1/app/?limit=10&offset='+ $scope.blogOffset * 20 +  '&format=json').then(function (results) { 
  20.        Array.prototype.push.apply($scope.blogs, results.objects); 
  21.        $scope.$broadcast('scroll.infiniteScrollComplete'); 
  22.      }) 
  23.    }; 
  24.  }) 

結果時間軸又錯了,人們總是超前一個時期做錯了一個在未來是正確的決定。人們遇到了網頁版的用戶授權問題,于是發明了JWT——Json Web Token。

然而,由于WebView在一些早期的Android手機上出現了性能問題,人們開始考慮替換方案。接著出現了兩個不同的解決方案:

  1. React Native
  2. 新的WebView——Crosswalk

開發人員開始歡呼React Native這樣的框架。但是,他們并沒有預見到人們正在厭惡APP,APP在我們的迭代里更新著,可能是一星期,可能是兩星期,又或者是一個月。誰說APP內自更新不是一件壞事,但是APP的提醒無時無刻不在干擾著人們的生活,噪聲越來越多。不要和用戶爭奪他們手機的使用權

一次構建,跨平臺運行

在我們需要學習C語言的時候,GCC就有了這樣的跨平臺編譯。

在我們開發桌面應用的時候,QT有就這樣的跨平臺能力。

在我們構建Web應用的時候,Java有這樣的跨平臺能力。

在我們需要開發跨平臺應用的時候,Cordova有這樣的跨平臺能力。

現在,React這樣的跨平臺框架又出現了,而響應式設計也是跨平臺式的設計。

響應式設計不得不提到的一個缺點是:他只是將原本在模板層做的事,放到了樣式(CSS)層。你還是在針對著不同的設備進行設計,兩種沒有什么多大的不同。復雜度不會消失,也不會憑空產生,它只會從一個物體轉移到另一個物體或一種形式轉為另一種形式。

React,將一小部分復雜度交由人來消化,將另外一部分交給了React自己來消化。在用Spring MVC之前,也許我們還在用CGI編程,而Spring降低了這部分復雜度,但是這和React一樣降低的只是新手的復雜度。在我們不能以某種語言的方式寫某相關的代碼時,這會帶來諸多麻煩。

RePractise

如果你是一只辛勤的蜜蜂,那么我想你應該都玩過上面那些技術。你是在練習前端的技術,還是在RePractise?如果你不花點時間整理一下過去,順便預測一下未來,那么你就是在白搭。

前端的演進在這一年特別快,Ruby On Rails也在一個合適的年代里出現,在那個年代里也流行得特別快。RoR開發效率高的優勢已然不再突顯,語法靈活性的副作用就是運行效率降低,同時后期維護難——每個人元編程了自己。

如果不能把Controller、Model Mapper變成ViewModel,又或者是Micro Services來解耦,那么ES6 + React只是在現在帶來更高的開發效率。而所謂的高效率,只是相比較而意淫出來的,因為他只是一層View層。將Model和Controller再加回View層,以后再拆分出來?

現有的結構只是將View層做了View層應該做的事。

首先,你應該考慮的是一種可以讓View層解耦于Domain或者Service層。今天,桌面、平板、手機并不是唯一用戶設備,雖然你可能在明年統一了這三個平臺,現在新的設備的出現又將設備分成兩種類型——桌面版和手機版。一開始桌面版和手機版是不同的版本,后來你又需要合并這兩個設備。

其次,你可以考慮用混合Micro Services優勢的Monolithic Service來分解業務。如果可以舉一個成功的例子,那么就是Linux,一個混合內核的“Service”。

***,Keep Learning。我們總需要在適當的時候做出改變,盡管我們覺得一個Web應用代碼庫中含桌面版和移動版代碼會很不錯,但是在那個時候需要做出改變。

對于復雜的應用來說,其架構肯定不是只有純MVP或者純MVVM這么簡單的。如果一個應用混合了MVVM、MVP和MVC,那么他也變成了MVC——因為他直接訪問了Model層。但是如果細分來看,只有訪問了Model層的那一部分才是MVC模式。

模式,是人們對于某個解決方案的描述。在一段代碼中可能有各種各樣的設計模式,更何況是架構。

責任編輯:倪明 來源: 簡書
相關推薦

2015-12-04 09:33:15

程序員前端演進史

2019-01-30 14:14:16

LinuxUNIX操作系統

2023-09-12 11:25:15

2015-05-19 14:34:17

程序員編程語言

2020-05-13 11:20:57

MySQL規范數據庫

2017-08-03 14:25:13

Python陷阱與缺陷

2012-06-28 14:01:30

Java程序員排序

2023-10-26 18:05:37

Git命令差異

2020-10-26 15:20:05

架構運維技術

2018-07-11 14:04:53

Python陷阱缺陷

2014-02-09 10:30:17

Python程序員工具

2023-05-11 08:01:08

Code開發保護機制

2024-12-04 10:12:06

2021-01-07 09:57:46

軟件架構服務器

2018-09-18 10:56:52

Android開發http

2020-11-25 10:40:58

程序員技能開發者

2025-11-11 02:25:00

MySQLbuffer文件系統

2020-03-31 08:42:14

程序員操作系統 Linux

2011-05-31 09:22:39

程序員

2019-07-23 17:20:02

Java微服務軟件架構模式
點贊
收藏

51CTO技術棧公眾號

亚洲精品动漫久久久久| 亚洲国产综合人成综合网站| 国产精品流白浆视频| 国产免费一区二区三区四区| 日韩欧美激情电影| 日韩欧美亚洲一二三区| 影音先锋在线亚洲| 午夜成人免费影院| 狠狠色丁香久久婷婷综合丁香| 欧美高清在线视频观看不卡| 精品无码人妻一区| 国产麻豆一区二区三区| 日韩欧美国产网站| 久久男人资源站| 97最新国自产拍视频在线完整在线看| 高清视频一区二区| 国产精品专区第二| 日韩熟女精品一区二区三区| 久久国产中文字幕| 亚洲乱码一区av黑人高潮| 中文字幕线观看| 忘忧草在线影院两性视频| ...xxx性欧美| 日本一区精品| 人成网站在线观看| 国产一区二区在线免费观看| 国产成人短视频| xxxx 国产| 婷婷丁香综合| 在线观看中文字幕亚洲| 毛片网站免费观看| av综合网页| 91精品欧美福利在线观看| www.亚洲天堂网| 理论片午夜视频在线观看| 亚洲欧美区自拍先锋| 亚洲欧美日产图| 欧美xxx.com| 99re66热这里只有精品3直播 | 伊人久久免费视频| 欧美成人三级伦在线观看| 欧美不卡在线观看| 91麻豆精品91久久久久同性| 91看片在线免费观看| 亚洲永久av| 激情成人在线视频| 玩弄中年熟妇正在播放| 成人性生交大片免费看网站 | 日韩三级视频在线播放| 欧美性久久久| 欧美高清在线观看| 久久午夜无码鲁丝片| 欧美69wwwcom| 欧美成人免费播放| 青娱乐国产在线视频| 亚洲国产精品成人| 欧美日本高清一区| 久久久久久福利| 好看不卡的中文字幕| 欧美国产欧美亚洲国产日韩mv天天看完整| 午夜三级在线观看| 一区二区三区四区日韩| 欧美成人精品h版在线观看| 精品国产国产综合精品| 国产国产精品| 欧美成人激情在线| 国产无码精品在线观看| 国产日韩亚洲| 国产成人精品在线播放| 国产精品露脸视频| 久久99精品国产麻豆婷婷| 国产在线视频2019最新视频| 99视频在线观看免费| 国产成人免费高清| 黄色91av| 福利片在线看| 亚洲三级在线免费| 欧美黄色免费网址| 超碰aⅴ人人做人人爽欧美| 欧美亚洲精品一区| 欧美国产在线一区| 超碰成人在线免费| 亚洲欧美国产精品专区久久 | 免费久久精品| 日韩中文字幕免费| 欧美人妻一区二区| 欧美亚洲三级| 成人午夜黄色影院| 免费观看黄色av| 国产亚洲一区二区三区在线观看| 亚洲欧美丝袜| 高h视频在线播放| 日本韩国一区二区| av在线免费观看不卡| 麻豆精品少妇| 国产香蕉精品视频一区二区三区| 国产三级aaa| 激情综合网址| 国产精品一区专区欧美日韩| 亚洲高清视频网站| 国产欧美一区二区精品性色 | 亚洲综合国产| 国产中文欧美精品| 你懂得网站在线| 伊人一区二区三区| 黄色国产小视频| 操欧美女人视频| 日韩在线视频观看| 黄色大片网站在线观看| 国产一区二区调教| 欧美一级二级三级| 少妇av在线| 欧美三区在线观看| 一起草在线视频| 先锋资源久久| 国产精品极品在线| 日韩专区第一页| 亚洲精品中文在线影院| 毛葺葺老太做受视频| 国产精品极品国产中出| 久久久国产精品视频| 亚洲欧美另类在线视频| 成人午夜碰碰视频| 婷婷四房综合激情五月| 国产精品电影| 精品久久一区二区三区| 日韩精品一区二区三区在线视频| 欧美专区一区二区三区| 国产美女在线精品免费观看| 国产盗摄在线观看| 欧美中文字幕一区| 人妻大战黑人白浆狂泄| 99精品国产99久久久久久福利| 亚洲一区二区三区在线视频 | 亚洲欧美日韩国产手机在线 | 亚洲人成电影网站色| 国产无遮挡又黄又爽| 国产精品自在欧美一区| 一区二区在线观| 久久影视精品| 一区二区三区亚洲| 69视频免费看| 国产亚洲一区字幕| 日本新janpanese乱熟| 国产精品亚洲人成在99www| 久久久亚洲网站| 农村少妇久久久久久久| 亚洲激情自拍偷拍| 国偷自产av一区二区三区麻豆| 91免费精品| 国产日韩欧美在线看| 日韩精品毛片| 欧美疯狂性受xxxxx喷水图片| 欧美成人短视频| 麻豆国产欧美日韩综合精品二区| 亚洲精品一区国产精品| 国模私拍国内精品国内av| 在线日韩中文字幕| 88av在线视频| 亚洲免费在线观看| 日韩大尺度视频| 亚洲毛片网站| 狠狠色噜噜狠狠狠狠色吗综合| 国产自产自拍视频在线观看| 精品视频久久久| 久久久久久无码精品大片| 国产欧美日韩卡一| 涩涩网站在线看| 午夜国产欧美理论在线播放| 高清国产一区| 小h片在线观看| 尤物九九久久国产精品的分类 | 日本在线播放一区| 成人午夜亚洲| 久久国产天堂福利天堂| 欧美一级性视频| 色呦呦国产精品| 三级黄色片在线观看| 国产一区二区三区黄视频| www.国产在线播放| 男男gay无套免费视频欧美| 国产精品亚发布| 99久久精品免费观看国产| 亚洲福利精品在线| www.日韩一区| 一区二区三区四区高清精品免费观看 | 在线观看v片| 中文字幕亚洲综合久久筱田步美| 国产精品污视频| 亚洲va国产天堂va久久en| 国产精品久久久久无码av色戒| 久久精品国产免费| 日本黄色片一级片| 红桃成人av在线播放| 亚洲在线www| 东京一区二区| 欧美另类第一页| 国产视频第一区| 日韩精品一区二区三区在线| 少妇高潮av久久久久久| 亚洲美女少妇撒尿| 精品人妻无码一区二区三区换脸| 狠狠色狠狠色综合系列| 岳毛多又紧做起爽| 欧美 日韩 国产精品免费观看| 欧美系列一区| 北条麻妃一区二区三区在线| 国产精品久在线观看| av免费不卡国产观看| 日韩中文字幕网| 日韩av成人| 精品国产91乱码一区二区三区| av网站免费播放| 美女高潮久久久| 成人性生活视频免费看| 999成人精品视频线3| 久久99精品久久久久久水蜜桃 | 在线观看欧美一区二区| 欧美中文日韩| 极品粉嫩国产18尤物| 五月综合激情| 少妇特黄a一区二区三区| 欧美色资源站| av资源站久久亚洲| 日本欧美在线| 国产精品国产福利国产秒拍| 日本免费一区二区六区| 欧美黑人极品猛少妇色xxxxx| 日日夜夜精品一区| 中文字幕精品网| 国产视频第一区| 亚洲欧洲成视频免费观看| 欧美一区二区公司| 日韩丝袜美女视频| 亚洲精品无码久久久久| 一道本成人在线| 国产免费av一区二区| 亚洲高清视频的网址| 欧美成人一二三区| 亚洲美女少妇撒尿| 超碰在线国产97| 中文字幕一区二区三区四区| 99精品全国免费观看| 国产校园另类小说区| 国产人成视频在线观看| 成人免费视频播放| 亚洲av永久无码精品| 国产成人精品免费在线| 国产91在线免费观看| 国产成人免费网站| youjizz.com日本| 国产91高潮流白浆在线麻豆 | 在线观看你懂的网站| 91久久免费观看| 欧美成人精品网站| 欧美午夜电影网| 亚洲影视一区二区| 欧美一区二区视频免费观看| 国产精品乱码一区二区| 91精品国产综合久久福利| 99产精品成人啪免费网站| 日韩一区二区三区视频在线| 性中国xxx极品hd| 亚洲国产精品va在看黑人| 天天操天天操天天| 亚洲区中文字幕| 色的视频在线免费看| 欧美成人精品xxx| 国产精品高颜值在线观看| 青草青草久热精品视频在线网站| 亚洲成人人体| 成人免费网站在线看| 高清日韩中文字幕| 日本婷婷久久久久久久久一区二区| 国产精品视频一区二区三区四蜜臂| 亚洲第一导航| 欧美国产专区| www.中文字幕在线| 蜜臀国产一区二区三区在线播放| 午夜一级免费视频| 成人精品鲁一区一区二区| 毛片网站免费观看| 亚洲视频香蕉人妖| 日韩久久久久久久久| 在线视频欧美区| 国产成人毛毛毛片| 亚洲精品一区中文字幕乱码| 自拍视频在线播放| 久久久久久国产精品美女| 免费成人直播| 91入口在线观看| 国产成人精品999在线观看| 熟女视频一区二区三区| 国产一区二区三区久久| 91视频这里只有精品| www.亚洲免费av| 国内毛片毛片毛片毛片毛片| 性做久久久久久免费观看欧美| 亚洲 小说区 图片区| 欧美精品一区二区三区蜜桃 | 欧美肥臀大乳一区二区免费视频| 涩涩视频在线免费看| 成人自拍性视频| 久久99影视| 妺妺窝人体色www看人体| 免费不卡在线观看| 在线观看国产网站| 亚洲男同性恋视频| 亚洲国产成人精品女人久久| 欧美不卡在线视频| 欧美a免费在线| 欧美综合激情网| 91大神精品| 在线看视频不卡| 久久激情久久| 亚洲国产精品狼友在线观看| 中文字幕一区二区在线播放| 69xxxx国产| 亚洲精品电影在线观看| 在线h片观看| 成人福利在线视频| 日韩激情一区| 免费大片在线观看| 波多野结衣在线一区| 黑鬼狂亚洲人videos| 欧美影视一区在线| 欧美女优在线观看| 97精品视频在线| 6080成人| 国产精品无码免费专区午夜| 国产一区二区三区高清播放| av免费播放网站| 在线一区二区三区做爰视频网站| 天堂av一区二区三区| 久久久久久久国产精品视频| 精品视频一区二区三区| 三年中文高清在线观看第6集| 奇米888四色在线精品| 91中文字幕永久在线| 欧美日韩国产专区| 亚洲av成人精品毛片| 97国产精品视频| 国产一区二区在线视频你懂的| 青青青在线观看视频| 高清久久久久久| 国产一级在线视频| 亚洲国产成人精品久久久国产成人一区| aa在线视频| 不卡一区二区三区四区五区| 欧美在线亚洲| 国产伦理在线观看| 亚洲国产精品天堂| 少妇高潮一区二区三区69| 久久久在线免费观看| 麻豆成人入口| 99热成人精品热久久66| 久久精品视频一区二区三区| 黄色片视频免费| 色哟哟入口国产精品| 日韩有码欧美| 日本a级片在线播放| 成人性生交大片免费看中文 | 国产精品免费区二区三区观看| 亚洲高清免费| aaaaa一级片| 欧美制服丝袜第一页| 黄网站视频在线观看| 操人视频欧美| 久久国产高清| 国产探花视频在线| 91麻豆精品国产自产在线| 四虎影视成人| 久久久综合亚洲91久久98| 日韩黄色在线观看| 性欧美疯狂猛交69hd| 精品国产91洋老外米糕| 欧美日韩电影免费看| youjizz.com亚洲| www.亚洲人| 中文字幕免费在线看| 欧美日本黄视频| 亚洲人成网站77777在线观看| 一级在线免费视频| 一区二区三区视频在线看| 青青草视频在线观看| 成人午夜高潮视频| 亚洲男女自偷自拍| 免费在线观看a级片| 精品国产凹凸成av人网站| 日产精品一区| 欧美这里只有精品| 国产欧美视频一区二区三区| 国产视频aaa| 日韩av片电影专区| 国内精品99| 2017亚洲天堂| 亚洲欧美中文字幕| 涩爱av色老久久精品偷偷鲁 | 日韩av电影网址| 中文字幕亚洲一区二区三区五十路|