<?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[ mobile - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ mobile - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 09 Sep 2026 16:53:47 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/mobile/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Mobile Background Execution: iOS Background Modes, Android WorkManager, and Background Services in Dart ]]>
                </title>
                <description>
                    <![CDATA[ Every mobile developer eventually hits the same wall: the app works perfectly when the user is looking at it. But the moment they press the home button, everything stops. A sync that should have compl ]]>
                </description>
                <link>https://www.freecodecamp.org/news/mobile-background-execution-ios-background-modes-android-workmanager-and-background-services-in-dart/</link>
                <guid isPermaLink="false">6a8c831fe5597860d219d150</guid>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ native ]]>
                    </category>
                
                    <category>
                        <![CDATA[ background jobs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Mon, 24 Aug 2026 17:45:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/2e9b068d-5fec-4228-8a0f-1f34bcd1e5f1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Every mobile developer eventually hits the same wall: the app works perfectly when the user is looking at it.</p>
<p>But the moment they press the home button, everything stops. A sync that should have completed in the background never ran. A notification that should have fired didn't. A file upload that started while the user was in the app failed silently the moment they switched away.</p>
<p>Background execution on mobile is one of the most misunderstood topics in the entire mobile engineering space. Most developers treat it like a simple problem: just keep the code running in the background. The platforms treat it like a resource management problem that directly affects battery life, performance, and the overall health of the device.</p>
<p>Understanding how iOS and Android actually think about background work, and then understanding how Flutter sits on top of both, is what separates engineers who fight the platform from engineers who work with it.</p>
<p>This article covers exactly that. You'll understand the native mechanisms on both platforms, the Flutter packages that bridge them, and when to reach for each approach.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-why-background-execution-is-hard">Why Background Execution is Hard</a></p>
</li>
<li><p><a href="#heading-how-flutter-runs-in-the-background">How Flutter Runs in the Background</a></p>
</li>
<li><p><a href="#heading-ios-background-execution">iOS Background Execution</a></p>
</li>
<li><p><a href="#heading-android-background-execution">Android Background Execution</a></p>
</li>
<li><p><a href="#heading-flutter-implementation">Flutter Implementation</a></p>
</li>
<li><p><a href="#heading-the-decision-framework">The Decision Framework</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>This article is written for mobile engineers building or maintaining production applications on iOS, Android, or Flutter. Before reading, you should be comfortable with:</p>
<ul>
<li><p>The basic lifecycle of a mobile app: what happens when the app moves between foreground, background, and suspended states</p>
</li>
<li><p>General mobile development concepts: you have shipped or maintained at least one mobile application on any platform or framework</p>
</li>
<li><p>Writing mobile applications in any framework: native iOS, native Android, Flutter, React Native, or any other mobile development stack</p>
</li>
<li><p>Multithreading and concurrency in your programming language of choice: understanding how your language handles work that runs outside the main thread is the foundation of everything this article covers</p>
</li>
</ul>
<p>If you're completely new to mobile development or have never had to think about threads and concurrent execution, start with those fundamentals first and return to this article when you are ready to think about production-grade background work.</p>
<h2 id="heading-why-background-execution-is-hard">Why Background Execution is Hard</h2>
<p>When your app is in the foreground, the platform gives it essentially full access to CPU, network, and memory. The user is actively looking at the app. Battery drain is expected. Resource usage is justified.</p>
<p>The moment the app goes to the background, the calculus changes completely. There are potentially dozens of apps installed on the device. If every one of them ran freely in the background, the battery would drain in hours. The CPU would be constantly active. Memory would fill up. The device would become hot and slow.</p>
<p>Both iOS and Android made a decision early on that background execution is a privilege, not a right. Apps must earn the right to run in the background by declaring what they need and why. The platform then decides how, when, and for how long to grant that access.</p>
<p>iOS and Android approached this problem differently but have been converging toward the same model over time: declared, categorized, and constrained background work that the platform controls.</p>
<h2 id="heading-how-flutter-runs-in-the-background">How Flutter Runs in the Background</h2>
<p>Before looking at iOS and Android separately, you need to understand something fundamental about how Flutter works.</p>
<p>Flutter runs your Dart code in a single main isolate. This isolate is attached to the platform's main thread. It handles your UI, your business logic, everything. When the app goes to the background, this main isolate can be suspended at any time.</p>
<p>When background work needs to happen in Flutter, the platform doesn't wake your main isolate. It wakes a separate, independent Dart isolate specifically for background execution. This background isolate runs in complete isolation from the main isolate.</p>
<h3 id="heading-what-this-means-practically">What This Means Practically:</h3>
<p>The background isolate has no access to the widget tree. You can't call setState, update any UI, or use any widget or BuildContext. It's pure Dart execution with no UI layer.</p>
<p>The background isolate doesn't share memory with the main isolate. Any data you need in the background must be persisted to disk (shared preferences, local database, files) and read by the background isolate independently.</p>
<p>The background isolate must be a top-level function or a static method. It can't be an anonymous function or a method on a class instance. The platform needs to be able to call this function by name when waking the app.</p>
<p>Understanding this changes how you think about background work in Flutter. You aren't keeping your app running. You're registering a separate piece of Dart code that the platform can invoke on its own schedule, in its own isolated environment.</p>
<h2 id="heading-ios-background-execution">iOS Background Execution</h2>
<h3 id="heading-what-ios-does-to-your-app">What iOS Does to Your App</h3>
<p>iOS manages your app through a set of clearly defined states.</p>
<p>When the user presses the home button, your app moves from foreground to background. iOS gives you a very brief window, typically five to ten seconds, to finish whatever you were doing. After that, your app is suspended. Suspended means completely frozen in memory. No Dart code runs. No network requests go out. The app exists in RAM but is essentially paused.</p>
<p>iOS can kill suspended apps at any time if it needs memory. When the user returns to your app, iOS either resumes it from suspension (fast) or relaunches it from scratch (slow). If your app was killed while suspended, the user won't know. The app just relaunches normally.</p>
<p>To do anything meaningful in the background on iOS, you must declare your intentions. iOS has a specific list of background capabilities, and your app must request exactly the ones it needs. Apple reviews these declarations during App Store submission.</p>
<h3 id="heading-bgtaskscheduler">BGTaskScheduler</h3>
<p>BGTaskScheduler is the modern iOS API for scheduling background work. Introduced in iOS 13, it replaced older and less reliable approaches. It gives you two types of tasks.</p>
<p>BGAppRefreshTask is for short, periodic background work. Think of it as iOS giving your app a brief wake-up to check for new content and update its state. You get approximately 30 seconds. iOS decides when to run the task based on the user's usage patterns. If the user opens your app every morning at 8am, iOS learns this and tries to run your refresh task just before 8am so content is ready when they arrive.</p>
<p>BGProcessingTask is for longer, heavier work. Database migrations, large file processing, or ML model updates. You get several minutes. These tasks only run when the device is plugged in and ideally on WiFi. You get more time but no guarantees on when the task actually runs.</p>
<p>The rules iOS enforces are strict.</p>
<p>You must declare your task identifiers in Info.plist under <code>BGTaskSchedulerPermittedIdentifiers</code> before the app ships. If the identifier isn't declared there, the task will never run regardless of what your code does.</p>
<p>You must register your task handler before <code>applicationDidFinishLaunching</code> completes. This happens before Flutter even initializes. The workmanager package handles this automatically, but it's important to understand why.</p>
<p>Every task must call <code>setTaskCompleted</code> when it finishes. If you don't call this, iOS marks the task as failed and becomes increasingly reluctant to schedule future tasks.</p>
<p>You should always set an expiration handler. If iOS decides to kill your task early, it calls the expiration handler first, giving you a brief moment to clean up, save state, and mark the task as incomplete so it gets rescheduled.</p>
<h3 id="heading-ios-background-modes">iOS Background Modes</h3>
<p>Beyond BGTaskScheduler, iOS has specific background modes for certain categories of apps. These are declared in Info.plist and enable continuous background execution for very specific purposes.</p>
<p>Audio and AirPlay keeps your app running as long as it's playing audio. The user sees now-playing controls on the lock screen. Podcast apps, music apps, and navigation apps with voice guidance use this. iOS is generous with this mode because the user clearly intends the audio to continue.</p>
<p>Location Updates allows continuous GPS access even when backgrounded. There are two levels. Significant location changes uses cell tower data and is battery-friendly. It fires when the device moves significantly, roughly 500 meters. Continuous location updates give precise GPS but drain battery. Apple scrutinizes location background mode during review. You need a genuine, user-facing reason.</p>
<p>Background Fetch is a legacy mechanism where iOS periodically wakes your app for a short window to fetch content. Unlike BGAppRefreshTask, this uses the older API. Most new apps should prefer BGTaskScheduler.</p>
<p>Remote Notifications with the <code>content-available</code> flag allows your server to trigger a brief background wake. When your server sends a silent push notification, iOS wakes your app to process it. This is how many apps stay current without constant polling.</p>
<h3 id="heading-the-ios-reality">The iOS Reality</h3>
<p>iOS background execution is fundamentally about trust. Apple trusts your app with background time if you declare what you need, use it for the declared purpose, and respect the time limits.</p>
<p>Exceed your time limit and iOS terminates your app. Request background modes you don't actually need and App Store review will flag it. Use location in the background for purposes not evident to the user and you will face rejection.</p>
<p>The watchdog timer is real. iOS monitors background tasks actively. Tasks that run too long, use too much CPU, or behave unexpectedly get terminated. Build your background tasks to be fast, focused, and respectful of system resources.</p>
<h2 id="heading-android-background-execution">Android Background Execution</h2>
<h3 id="heading-what-android-does-to-your-app">What Android Does to Your App</h3>
<p>Android manages process priority through a hierarchy. Foreground apps get the highest priority. Apps with running services get elevated priority. Background apps have lower priority. Empty processes and apps with no active components have the lowest priority.</p>
<p>When the system needs memory, it kills processes in order of priority, starting from the lowest. Your background app can be killed at any time. An app with a foreground service is much harder to kill. An active foreground app is essentially never killed by the system.</p>
<p>Android was historically more permissive than iOS. Early Android allowed apps to run services indefinitely in the background. This freedom was abused. Apps ran constantly even when the user hadn't interacted with them in weeks. Battery life suffered, and Android had to respond.</p>
<p>Starting with Android 8.0 Oreo, Google began restricting background services. Apps can no longer start background services when the app itself isn't in the foreground. Each subsequent Android version has tightened these restrictions further. Android is converging toward iOS's model of declared, constrained background work.</p>
<h3 id="heading-foreground-services">Foreground Services</h3>
<p>A foreground service is the most reliable form of background execution on Android. It runs continuously and must display a persistent notification. The notification is mandatory. It's how Android communicates to the user that something is actively happening. The user can see it, expand it for details, and stop it if they choose.</p>
<p>Music players show the currently playing track with playback controls. Navigation apps show the current route with estimated arrival time. File upload apps show a progress bar. Fitness apps show elapsed time and current stats.</p>
<p>Android 14 introduced foreground service types. You must now declare what kind of foreground service you're running. The types are: mediaPlayback, location, dataSync, camera, microphone, phoneCall, remoteMessaging, shortService, health, and systemExempted. This is Android deliberately moving toward the iOS model of declared categories.</p>
<p>Foreground services are the right choice when the user expects something to be actively happening. Playing music. Navigating. Uploading a file. Anything where there is an ongoing activity that the user initiated and expects to continue.</p>
<h3 id="heading-workmanager">WorkManager</h3>
<p>WorkManager is Google's recommended solution for deferrable, guaranteed background work. The key characteristics that define it are important to understand.</p>
<p>Guaranteed means your work will eventually run. Even if the app exits, the user restarts the device, or the system kills your process, WorkManager persists the task to a local database and retries it when conditions allow. This is fundamentally different from a background service that disappears if the app is killed.</p>
<p>Deferrable means you don't control exactly when the work runs. You define constraints and WorkManager waits until those constraints are satisfied. Constraints can include requiring network connectivity, requiring the device to be charging, or requiring the battery to not be low. WorkManager picks the optimal time within those constraints.</p>
<p>Periodic tasks have a minimum interval of 15 minutes. This is enforced by the platform, not WorkManager. Android doesn't allow apps to schedule work more frequently than this to prevent battery abuse.</p>
<p>Under the hood, WorkManager uses JobScheduler on modern Android. It manages the complexity of backward compatibility and constraint handling for you.</p>
<p>WorkManager is the right choice for: syncing data with a server, uploading logs or analytics, processing downloaded files, cleaning up old cache entries, generating thumbnails, or sending queued messages.</p>
<p>WorkManager is the wrong choice for anything that needs to run immediately, at an exact time, or continuously.</p>
<h3 id="heading-doze-mode-and-app-standby">Doze Mode and App Standby</h3>
<p>Doze Mode activates when the device is unplugged, stationary, and the screen has been off for an extended period. In Doze, Android suspends network access, defers WorkManager tasks, ignores wake locks, and defers alarms. The system enters this state to conserve battery when the device is clearly not being used.</p>
<p>The system exits Doze periodically for maintenance windows during which deferred work can run. These windows become less frequent the longer the device stays in Doze.</p>
<p>Only high-priority Firebase Cloud Messaging notifications can break through Doze. This is why server-triggered background refresh is so powerful: your server sends a high-priority FCM message, Android wakes the app even in Doze to process it.</p>
<p>App Standby Buckets categorize your app based on how recently and frequently the user has interacted with it. The buckets are Active, Working Set, Frequent, Rare, and Restricted. The bucket your app is in directly affects how much background work it is allowed to do.</p>
<p>Active means the user used your app very recently. Full background execution allowed.</p>
<p>Working Set means the user uses your app regularly. Slight restrictions on how frequently background work can run.</p>
<p>Frequent means the user uses your app often but not daily. More restrictions.</p>
<p>Rare means the user barely uses your app. Significant restrictions. WorkManager tasks get delayed substantially.</p>
<p>Restricted means the app has been flagged for bad behavior or is almost never used. Background work is heavily throttled. The user or the system has effectively put your app on notice.</p>
<p>If your app ends up in the Rare or Restricted bucket, background sync becomes unreliable. The way to avoid this is straightforward: build an app people actually use regularly.</p>
<h2 id="heading-flutter-implementation">Flutter Implementation</h2>
<p>Now let's look at how Flutter engineers implement background work using the native mechanisms above.</p>
<h3 id="heading-setup-project-structure">Setup: Project Structure</h3>
<p>Background work in Flutter requires coordination between your Dart code and the native platform. The packages handle most of this, but there are configuration steps on both the iOS and Android sides that you must complete for the work to actually run.</p>
<h4 id="heading-workmanager"><code>workmanager</code></h4>
<p>The workmanager package is the most widely used solution for deferrable background tasks in Flutter. It wraps Android WorkManager and iOS BGTaskScheduler.</p>
<p>Add the dependency:</p>
<pre><code class="language-yaml">dependencies:
  workmanager: ^0.5.2
</code></pre>
<p>On Android, no additional configuration is needed beyond the dependency. WorkManager is part of AndroidX and is available on all modern Android devices.</p>
<p>On iOS, add your task identifiers to Info.plist:</p>
<pre><code class="language-xml">&lt;key&gt;BGTaskSchedulerPermittedIdentifiers&lt;/key&gt;
&lt;array&gt;
  &lt;string&gt;com.yourapp.syncTask&lt;/string&gt;
  &lt;string&gt;com.yourapp.cleanupTask&lt;/string&gt;
&lt;/array&gt;
</code></pre>
<p>Also add Background Modes capability in Xcode and enable Background fetch and Background processing.</p>
<p>The background callback must be a top-level function. It can't be inside a class:</p>
<pre><code class="language-dart">@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((taskName, inputData) async {
    switch (taskName) {
      case 'syncUserData':
        await syncUserData(inputData);
        break;
      case 'cleanupOldFiles':
        await cleanupOldFiles();
        break;
      default:
        print('Unknown task: $taskName');
    }
    return Future.value(true);
  });
}
</code></pre>
<p>The <code>@pragma('vm:entry-point')</code> annotation is critical. Without it, the Dart tree shaker may remove this function during release builds because it appears to be uncalled from Dart code. The platform calls it by name, not through Dart, so the tree shaker can't detect the reference.</p>
<p>Returning <code>true</code> from the task tells WorkManager the task succeeded. Returning <code>false</code> tells it the task failed and should be retried.</p>
<p>Initialize workmanager in your main function:</p>
<pre><code class="language-dart">void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Workmanager().initialize(
    callbackDispatcher,
    isInDebugMode: kDebugMode,
  );

  runApp(const MyApp());
}
</code></pre>
<p><code>isInDebugMode: true</code> logs detailed information about task scheduling and execution. Turn this off in production.</p>
<p>Registering a one-time task:</p>
<pre><code class="language-dart">Future&lt;void&gt; scheduleDataSync() async {
  await Workmanager().registerOneOffTask(
    'syncUserData',
    'syncUserData',
    initialDelay: const Duration(minutes: 5),
    constraints: Constraints(
      networkType: NetworkType.connected,
      requiresBatteryNotLow: true,
    ),
    inputData: {
      'userId': currentUser.id,
      'syncType': 'full',
    },
  );
}
</code></pre>
<p>The task will run once, after a minimum 5-minute delay, only when the device has network connectivity and the battery isn't low. The inputData map is passed to the callback and available as the <code>inputData</code> parameter in <code>executeTask</code>.</p>
<p>Registering a periodic task:</p>
<pre><code class="language-dart">Future&lt;void&gt; schedulePeriodicSync() async {
  await Workmanager().registerPeriodicTask(
    'periodicSync',
    'syncUserData',
    frequency: const Duration(hours: 1),
    constraints: Constraints(
      networkType: NetworkType.connected,
    ),
  );
}
</code></pre>
<p>The minimum frequency is 15 minutes enforced by the platform. If you set a shorter interval, it gets rounded up to 15 minutes. On iOS, BGTaskScheduler controls the actual timing and may run the task less frequently based on device conditions.</p>
<p>Cancelling tasks:</p>
<pre><code class="language-dart">// cancel one specific task
await Workmanager().cancelByUniqueName('periodicSync');

// cancel all registered tasks
await Workmanager().cancelAll();
</code></pre>
<h4 id="heading-flutterbackgroundservice"><code>flutter_background_service</code></h4>
<p>The workmanager package is great for deferrable work, but sometimes you need something that runs continuously, like a health monitor, a real-time data collector, or a persistent connection.</p>
<p>For that, flutter_background_service creates a long-running service. On Android, this becomes a Foreground Service with a persistent notification. On iOS, it uses a combination of background modes.</p>
<p>Add the dependency:</p>
<pre><code class="language-yaml">dependencies:
  flutter_background_service: ^5.0.5
  flutter_local_notifications: ^17.0.0
</code></pre>
<p>The background service entry point, again, must be a top-level function:</p>
<pre><code class="language-dart">@pragma('vm:entry-point')
void onStart(ServiceInstance service) async {
  DartPluginRegistrant.ensureInitialized();

  if (service is AndroidServiceInstance) {
    service.on('setAsForeground').listen((event) {
      service.setAsForegroundService();
    });

    service.on('setAsBackground').listen((event) {
      service.setAsBackgroundService();
    });
  }

  service.on('stopService').listen((event) {
    service.stopSelf();
  });

  // your actual background work runs here
  Timer.periodic(const Duration(seconds: 30), (timer) async {
    if (service is AndroidServiceInstance) {
      if (await service.isForegroundService()) {
        service.setForegroundNotificationInfo(
          title: 'App is running',
          content: 'Last sync: ${DateTime.now()}',
        );
      }
    }

    // do the actual work
    await performBackgroundSync();

    // send data to the main isolate if needed
    service.invoke('update', {
      'lastSync': DateTime.now().toIso8601String(),
    });
  });
}
</code></pre>
<p>Initialize the service:</p>
<pre><code class="language-dart">Future&lt;void&gt; initializeBackgroundService() async {
  final service = FlutterBackgroundService();

  const AndroidNotificationChannel channel = AndroidNotificationChannel(
    'background_service',
    'Background Service',
    description: 'This channel is used for the background service notification',
    importance: Importance.low,
  );

  final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation&lt;
          AndroidFlutterLocalNotificationsPlugin&gt;()
      ?.createNotificationChannel(channel);

  await service.configure(
    androidConfiguration: AndroidConfiguration(
      onStart: onStart,
      autoStart: true,
      isForegroundMode: true,
      notificationChannelId: 'background_service',
      initialNotificationTitle: 'App Running',
      initialNotificationContent: 'Background sync active',
      foregroundServiceNotificationId: 888,
    ),
    iosConfiguration: IosConfiguration(
      autoStart: true,
      onForeground: onStart,
      onBackground: onIosBackground,
    ),
  );

  await service.startService();
}
</code></pre>
<p>Communicating between the background service and your UI:</p>
<pre><code class="language-dart">// in your widget, listen for updates from the background service
class HomeScreen extends StatefulWidget {
  @override
  State&lt;HomeScreen&gt; createState() =&gt; _HomeScreenState();
}

class _HomeScreenState extends State&lt;HomeScreen&gt; {
  String lastSync = 'Never';

  @override
  void initState() {
    super.initState();
    FlutterBackgroundService().on('update').listen((event) {
      setState(() {
        lastSync = event?['lastSync'] ?? 'Unknown';
      });
    });
  }

  void stopService() {
    FlutterBackgroundService().invoke('stopService');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Text('Last sync: $lastSync'),
          ElevatedButton(
            onPressed: stopService,
            child: const Text('Stop Background Service'),
          ),
        ],
      ),
    );
  }
}
</code></pre>
<p>The <code>invoke</code> and <code>on</code> methods create a two-way communication channel between the background isolate and the main isolate. The background service invokes events with data. The UI listens for those events and updates accordingly.</p>
<h4 id="heading-backgroundfetch"><code>background_fetch</code></h4>
<p>For simpler periodic background work where workmanager's full constraint system is more than you need, background_fetch provides a cleaner API.</p>
<pre><code class="language-yaml">dependencies:
  background_fetch: ^1.2.1
</code></pre>
<pre><code class="language-dart">void main() {
  runApp(const MyApp());
  BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
}

@pragma('vm:entry-point')
void backgroundFetchHeadlessTask(HeadlessTask task) async {
  String taskId = task.taskId;
  bool isTimeout = task.timeout;

  if (isTimeout) {
    BackgroundFetch.finish(taskId);
    return;
  }

  await performQuickSync();
  BackgroundFetch.finish(taskId);
}
</code></pre>
<p>Configure and start:</p>
<pre><code class="language-dart">Future&lt;void&gt; configureBackgroundFetch() async {
  await BackgroundFetch.configure(
    BackgroundFetchConfig(
      minimumFetchInterval: 15,
      stopOnTerminate: false,
      enableHeadless: true,
      requiresBatteryNotLow: false,
      requiresCharging: false,
      requiresStorageNotLow: false,
      requiresDeviceIdle: false,
      requiredNetworkType: NetworkType.ANY,
    ),
    (taskId) async {
      await performQuickSync();
      BackgroundFetch.finish(taskId);
    },
    (taskId) async {
      // timeout handler
      BackgroundFetch.finish(taskId);
    },
  );
}
</code></pre>
<p>Calling <code>BackgroundFetch.finish(taskId)</code> is mandatory. On iOS, failing to call finish tells the platform your task did not complete correctly, which affects future scheduling. On Android, it signals WorkManager that the task is done.</p>
<h3 id="heading-persisting-data-between-isolates">Persisting Data Between Isolates</h3>
<p>Since the background isolate and the main isolate don't share memory, data must be persisted to disk.</p>
<p>The most common approaches are shared_preferences for simple key-value data and a local database like sqflite or isar for structured data.</p>
<pre><code class="language-dart">// writing from background isolate
@pragma('vm:entry-point')
void callbackDispatcher() {
  Workmanager().executeTask((taskName, inputData) async {
    final prefs = await SharedPreferences.getInstance();

    // fetch new data
    final newData = await fetchFromServer();

    // persist for main isolate to read
    await prefs.setString('lastSyncData', jsonEncode(newData));
    await prefs.setString('lastSyncTime', DateTime.now().toIso8601String());

    return Future.value(true);
  });
}

// reading in main isolate when app comes to foreground
class HomeScreen extends StatefulWidget {
  @override
  State&lt;HomeScreen&gt; createState() =&gt; _HomeScreenState();
}

class _HomeScreenState extends State&lt;HomeScreen&gt; {
  @override
  void initState() {
    super.initState();
    loadLastSyncedData();
  }

  Future&lt;void&gt; loadLastSyncedData() async {
    final prefs = await SharedPreferences.getInstance();
    final data = prefs.getString('lastSyncData');
    final syncTime = prefs.getString('lastSyncTime');

    if (data != null) {
      setState(() {
        // update your state with the synced data
      });
    }
  }
}
</code></pre>
<h2 id="heading-the-decision-framework">The Decision Framework</h2>
<p>Given a background task requirement, here is how to decide which approach to reach for:</p>
<p>Does the user expect something to actively be running, like music playing, navigation running, or a file uploading? Use a Foreground Service via flutter_background_service. The persistent notification isn't just a requirement, it's straightforward communication to the user about what the app is doing.</p>
<p>Does the work need to happen eventually but not necessarily right now? Something like syncing data, uploading logs, processing files, or cleaning the cache. If so, use workmanager. It guarantees the work runs, respects constraints, and survives app restarts and device reboots.</p>
<p>Does the work need to happen on a server-triggered signal? Use Firebase Cloud Messaging with a high-priority silent notification. Your server sends the signal, iOS and Android wake your app, your background isolate handles the work. This breaks through Doze Mode on Android and works with iOS's silent push mechanism.</p>
<p>Does the work need to happen on a simple periodic schedule with minimal constraints? Use background_fetch for a simpler API when workmanager's full constraint system is more than you need.</p>
<p>Does the work need precise timing? Rethink whether it truly needs to happen in the background. If a user sets a reminder for 3pm, a local notification is the right approach. The notification fires at the exact time regardless of whether the app is in the background.</p>
<p>One note about iOS specifically: no Flutter package can work around Apple's restrictions. If you register a BGAppRefreshTask, iOS decides when it runs. If you set constraints on WorkManager, Android decides when they're satisfied. The platform is in control. Your job is to declare what you need clearly, handle it correctly when the platform gives you the window, and build your app to be resilient when the background work runs later than expected.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Background execution on mobile isn't a Flutter problem or a Dart problem. It's a platform problem that Flutter sits on top of.</p>
<p>iOS is restrictive by design. You declare the specific category of background work you need. Apple evaluates whether that use case is legitimate. When granted, the platform gives you controlled, time-limited windows. Exceed those windows and the system terminates your task.</p>
<p>Android started permissive and has been getting stricter with every major version. Foreground Services give reliable continuous execution with a visible notification. WorkManager gives guaranteed deferred execution with constraints. Doze Mode and App Standby Buckets restrict everything else based on device state and user behavior.</p>
<p>Flutter bridges both through packages that map to the native APIs. workmanager covers deferrable work on both platforms. flutter_background_service covers continuous work with a foreground notification. background_fetch covers simple periodic work with a cleaner API.</p>
<p>The engineers who succeed with mobile background work are the ones who understand what the platform is actually doing and design with those constraints in mind. They don't fight the platform. They declare what they need, handle the windows they're given, persist state properly across isolate boundaries, and build their systems to be resilient when background work is delayed or deferred.</p>
<p>That's how background work actually gets done on mobile.</p>
<p>Understanding the core of background processes and app lifecycle in native and hybrid mobile engineering helps you make an informed architectural decision when selecting the task handler needed to run a specific task.</p>
<p>Happy Coding!!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A Deep Dive into Behavioral Patterns: The Visitor Design Pattern and its Clean Operations Across Complex Object Structures ]]>
                </title>
                <description>
                    <![CDATA[ There's a problem that shows up in almost every growing software system, and most developers don't even realize they're hitting it until the damage is already done. You have a set of objects: differen ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-visitor-design-pattern-and-its-clean-operations-across-complex-object-structures/</link>
                <guid isPermaLink="false">6a74b21fcf90c22a668963b6</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design patterns ]]>
                    </category>
                
                    <category>
                        <![CDATA[ design principles ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Dart ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mobile Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software architecture ]]>
                    </category>
                
                    <category>
                        <![CDATA[ visitor design pattern ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oluwaseyi Fatunmole ]]>
                </dc:creator>
                <pubDate>Thu, 06 Aug 2026 16:11:11 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/ff25cbd5-72fc-4f17-8d37-ba8dc909de46.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There's a problem that shows up in almost every growing software system, and most developers don't even realize they're hitting it until the damage is already done.</p>
<p>You have a set of objects: different types, shapes, and data. And at some point, someone asks you to perform an operation on all of them, like exporting them them to PDF, sending them a notification, generating a report, or calculating their fees.</p>
<p>Your first instinct might be to write a function that checks the type and branches accordingly, like an if-else block or switch statement. Something that says: if this is a NewUser, do this. If this is a JointAccountUser, do that. It works, you ship it, and everyone is happy.</p>
<p>Then another operation comes in. And another. Every single time, you go back to the same place and add another branch. The function grows. The class grows. The test surface grows. What started as a clean model is now a god object that knows how to do everything for everyone.</p>
<p>The Visitor Design Pattern exists to break this cycle completely.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-what-is-the-visitor-design-pattern">What is the Visitor Design Pattern?</a></p>
</li>
<li><p><a href="#heading-the-problem-the-visitor-pattern-solves">The Problem the Visitor Pattern Solves</a></p>
</li>
<li><p><a href="#heading-core-components">Core Components</a></p>
</li>
<li><p><a href="#heading-real-world-example-one-document-export">Real World Example One: Document Export</a></p>
</li>
<li><p><a href="#heading-real-world-example-two-notification-system">Real World Example Two: Notification System</a></p>
</li>
<li><p><a href="#heading-real-world-example-three-fee-calculation">Real World Example Three: Fee Calculation</a></p>
</li>
<li><p><a href="#heading-the-power-of-combining-all-three-operations">The Power of Combining All Three Operations</a></p>
</li>
<li><p><a href="#heading-when-to-use-the-visitor-pattern">When to Use the Visitor Pattern</a></p>
</li>
<li><p><a href="#heading-when-not-to-use-it">When Not to Use It</a></p>
</li>
<li><p><a href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-the-visitor-design-pattern">What is the Visitor Design Pattern?</h2>
<p>The Visitor pattern is a behavioral design pattern that lets you define a new operation on a family of objects without changing the objects themselves.</p>
<p>The key word there is behavioral. Behavioral patterns are about how objects communicate and distribute responsibility. Where creational patterns deal with how objects are created and structural patterns deal with how they are composed, behavioral patterns deal with how they interact and who is responsible for what.</p>
<p>The Visitor pattern specifically deals with the question of who should own an operation when that operation needs to work differently across multiple object types.</p>
<p>The classic answer is: put the operation on each object. Give each class a method that handles the operation for its own type. But this breaks down the moment you have multiple operations, because now every new operation means touching every class. You're spreading one concern across your entire object hierarchy.</p>
<p>The Visitor pattern flips this. Instead of spreading the operation across the objects, you collect it into one place called a Visitor. The objects simply accept the visitor and let it do its work. Adding a new operation means creating a new Visitor. The existing objects don't change at all.</p>
<p>This is the Open/Closed Principle working exactly as intended: open for extension, closed for modification.</p>
<h2 id="heading-the-problem-the-visitor-pattern-solves">The Problem the Visitor Pattern Solves</h2>
<p>Let me show you exactly what this looks like without the Visitor pattern.</p>
<p>Say you have a fintech platform with four types of users: existing customers, new customers, minor account holders, and joint account holders. Your product manager comes in and asks you to add document export. Every user type should be exportable to PDF, Excel, and CSV.</p>
<p>Without Visitor, the natural approach looks something like this:</p>
<pre><code class="language-dart">class ExistingUser {
  final int id;
  final String firstName;
  final String lastName;
  final DateTime lastPaymentDate;
  final num accountBalance;

  String exportToPdf() {
    return '$firstName\n$lastName\n$lastPaymentDate\n$accountBalance';
  }

  String exportToExcel() {
    return '$firstName,$lastName,$lastPaymentDate,$accountBalance';
  }

  String exportToCsv() {
    return '"$firstName","$lastName","$lastPaymentDate","$accountBalance"';
  }
}
</code></pre>
<p>And you repeat this for NewUser, MinorAccountUser, and JointAccountUser. Twelve methods spread across four classes just for document export.</p>
<p>Now the product manager comes back. They want notifications: email, SMS, and Push. Back you go to all four classes, adding three more methods each. Twelve more methods spread across the same four classes.</p>
<p>Then they want fee calculation. Then they want KYC status checks. Every new operation multiplies across every user type. The classes grow, the reasons to change multiply, and testing becomes painful.</p>
<p>This is the exact problem the Visitor pattern was built to solve.</p>
<h2 id="heading-core-components">Core Components</h2>
<p>The Visitor pattern has four core components. Understanding each one before looking at code makes the implementation much easier to follow.</p>
<h3 id="heading-the-visitor-interface">The Visitor Interface</h3>
<p>This is the contract that every visitor must implement. It declares one method per object type it needs to visit. A visitor that handles four user types declares four visit methods, one for each type.</p>
<h3 id="heading-the-concrete-visitors">The Concrete Visitors</h3>
<p>These are the real implementations of the Visitor interface. Each one represents a single operation and knows how to handle every object type. A PdfHandler is a concrete visitor. An ExcelHandler is a concrete visitor. A SmsNotificationHandler is a concrete visitor. Each one has one job and knows how to do that job for every user type.</p>
<h3 id="heading-the-consumer-interface-also-called-element-or-acceptor">The Consumer Interface (also called Element or Acceptor)</h3>
<p>This is the contract that every object in the hierarchy must implement. It declares a single accept method that takes a Visitor and calls the right visit method on it. This is the double dispatch mechanism that makes the pattern work.</p>
<h3 id="heading-the-concrete-consumers">The Concrete Consumers</h3>
<p>These are the real objects in the hierarchy: ExistingCustomers, NewCustomers, MinorCustomer, and JointCustomer. Each one implements accept by calling the specific visit method that corresponds to its own type.</p>
<p>Think of it this way. The Visitor interface is implemented by every operation you want to perform: PdfHandler, ExcelHandler, and CsvHandler. Each of these knows how to handle all four user types.</p>
<p>The Consumer interface is implemented by every object in the hierarchy: ExistingCustomers, NewCustomers, MinorCustomer, and JointCustomer. Each of these knows how to receive a visitor and route it to the correct method.</p>
<p>When you call <code>existingCustomer.accept(pdfHandler)</code>, ExistingCustomers calls <code>pdfHandler.visitExistingCustomer(this)</code> and passes itself as the argument. The right method fires automatically. There's no type checking, if-else, or switch. The object tells the visitor who it is, and the visitor knows exactly what to do with that information.</p>
<h2 id="heading-real-world-example-one-document-export">Real World Example One: Document Export</h2>
<p>This is a real scenario from a fintech platform. There are four user types with different data structures, all needing to export their information to three document formats: PDF, Excel, and CSV.</p>
<h3 id="heading-step-1-define-the-user-models">Step 1: Define the User Models</h3>
<pre><code class="language-dart">class ExistingUser {
  final int id;
  final String firstName;
  final String lastName;
  final DateTime lastPaymentDate;
  final num accountBalance;

  const ExistingUser({
    required this.id,
    required this.firstName,
    required this.lastName,
    required this.lastPaymentDate,
    required this.accountBalance,
  });
}

class NewUser {
  final String firstName;
  final String lastName;

  const NewUser({
    required this.firstName,
    required this.lastName,
  });
}

class MinorAccountUser {
  final int age;
  final int guardianId;
  final String firstName;
  final String lastName;
  final String guardianName;

  const MinorAccountUser({
    required this.age,
    required this.guardianId,
    required this.firstName,
    required this.lastName,
    required this.guardianName,
  });
}

class JointAccountUser {
  final int jointAccountId;
  final List&lt;String&gt; accountHoldersInfo;
  final num accountBalance;

  const JointAccountUser({
    required this.jointAccountId,
    required this.accountHoldersInfo,
    required this.accountBalance,
  });
}
</code></pre>
<p>We have four models. Each one owns its own data and nothing else. There's no export logic or notification logic. And no business operations of any kind. Just clean data structures.</p>
<p>This is exactly how it should be. The model's job is to hold data. The visitor's job is to operate on it.</p>
<h3 id="heading-step-2-define-the-visitor-and-consumer-interfaces">Step 2: Define the Visitor and Consumer Interfaces</h3>
<pre><code class="language-dart">abstract class UserVisitor&lt;T&gt; {
  T visitExistingCustomer(ExistingUser user);
  T visitNewCustomer(NewUser user);
  T visitMinorCustomer(MinorAccountUser user);
  T visitJointCustomer(JointAccountUser user);
}

abstract class UserConsumer {
  T accept&lt;T&gt;(UserVisitor&lt;T&gt; visitor);
}
</code></pre>
<p><code>UserVisitor&lt;T&gt;</code> is generic. The type parameter <code>T</code> represents what the visitor returns. A document export visitor returns a String. A fee calculation visitor might return a double. A validation visitor might return a bool. The same pattern works for any return type.</p>
<p><code>UserConsumer</code> declares the accept method. Every object in the hierarchy must implement this. The accept method is what makes the double dispatch work. The object receives the visitor and immediately calls the right visit method on it, passing itself as the argument.</p>
<h3 id="heading-step-3-implement-the-concrete-consumers">Step 3: Implement the Concrete Consumers</h3>
<pre><code class="language-dart">class ExistingCustomers implements UserConsumer {
  final ExistingUser user;
  ExistingCustomers({required this.user});

  @override
  T accept&lt;T&gt;(UserVisitor&lt;T&gt; visitor) {
    return visitor.visitExistingCustomer(user);
  }
}

class NewCustomers implements UserConsumer {
  final NewUser user;
  NewCustomers({required this.user});

  @override
  T accept&lt;T&gt;(UserVisitor&lt;T&gt; visitor) {
    return visitor.visitNewCustomer(user);
  }
}

class MinorCustomer implements UserConsumer {
  final MinorAccountUser user;
  MinorCustomer({required this.user});

  @override
  T accept&lt;T&gt;(UserVisitor&lt;T&gt; visitor) {
    return visitor.visitMinorCustomer(user);
  }
}

class JointCustomer implements UserConsumer {
  final JointAccountUser user;
  JointCustomer({required this.user});

  @override
  T accept&lt;T&gt;(UserVisitor&lt;T&gt; visitor) {
    return visitor.visitJointCustomer(user);
  }
}
</code></pre>
<p>Each consumer wraps one user model and implements accept by forwarding to the correct visit method. This is the entire job of a concrete consumer. It knows who it is, and it tells the visitor by calling the right method.</p>
<p>Notice that none of these classes know anything about PDF, Excel, CSV, email, SMS, or any operation. They're completely decoupled from every operation that will ever be performed on them.</p>
<h3 id="heading-step-4-implement-the-concrete-visitors">Step 4: Implement the Concrete Visitors</h3>
<pre><code class="language-dart">class PdfHandler implements UserVisitor&lt;String&gt; {
  @override
  String visitExistingCustomer(ExistingUser user) {
    return '${user.firstName} ${user.lastName}'
        '\nBalance: ${user.accountBalance}'
        '\nLast Payment: ${user.lastPaymentDate}';
  }

  @override
  String visitNewCustomer(NewUser user) {
    return '${user.firstName} ${user.lastName}';
  }

  @override
  String visitMinorCustomer(MinorAccountUser user) {
    return '${user.firstName} ${user.lastName}'
        '\nAge: ${user.age}'
        '\nGuardian: ${user.guardianName} (ID: ${user.guardianId})';
  }

  @override
  String visitJointCustomer(JointAccountUser user) {
    final holders = user.accountHoldersInfo.join(', ');
    return 'Joint Account ID: ${user.jointAccountId}'
        '\nHolders: $holders'
        '\nBalance: ${user.accountBalance}';
  }
}

class ExcelHandler implements UserVisitor&lt;String&gt; {
  @override
  String visitExistingCustomer(ExistingUser user) {
    return '${user.firstName}\t${user.lastName}'
        '\t${user.accountBalance}\t${user.lastPaymentDate}';
  }

  @override
  String visitNewCustomer(NewUser user) {
    return '${user.firstName}\t${user.lastName}';
  }

  @override
  String visitMinorCustomer(MinorAccountUser user) {
    return '${user.firstName}\t${user.lastName}'
        '\t${user.age}\t${user.guardianName}\t${user.guardianId}';
  }

  @override
  String visitJointCustomer(JointAccountUser user) {
    final holders = user.accountHoldersInfo.join('\t');
    return '${user.jointAccountId}\t$holders\t${user.accountBalance}';
  }
}

class CsvHandler implements UserVisitor&lt;String&gt; {
  @override
  String visitExistingCustomer(ExistingUser user) {
    return '"${user.firstName}","${user.lastName}"'
        ',"${user.accountBalance}","${user.lastPaymentDate}"';
  }

  @override
  String visitNewCustomer(NewUser user) {
    return '"${user.firstName}","${user.lastName}"';
  }

  @override
  String visitMinorCustomer(MinorAccountUser user) {
    return '"${user.firstName}","${user.lastName}"'
        ',"${user.age}","${user.guardianName}","${user.guardianId}"';
  }

  @override
  String visitJointCustomer(JointAccountUser user) {
    final holders = user.accountHoldersInfo.map((h) =&gt; '"$h"').join(',');
    return '"${user.jointAccountId}",$holders,"${user.accountBalance}"';
  }
}
</code></pre>
<p>Each handler implements the visitor interface and knows exactly how to format each user type for its specific document format. PdfHandler uses newlines and labels. ExcelHandler uses tabs. CsvHandler wraps values in quotes and separates with commas.</p>
<p>The formatting logic for each document type lives in exactly one class. If the PDF format changes, you touch only PdfHandler. If the CSV format changes, you touch only CsvHandler. The user models never change.</p>
<h3 id="heading-step-5-use-it">Step 5: Use It</h3>
<pre><code class="language-dart">void existingUserLogic() {
  final customer = ExistingCustomers(
    user: ExistingUser(
      id: 10,
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
      lastPaymentDate: DateTime.now(),
      accountBalance: 7373773.39,
    ),
  );

  final pdf = customer.accept(PdfHandler());
  final excel = customer.accept(ExcelHandler());
  final csv = customer.accept(CsvHandler());

  print('PDF:\n$pdf\n');
  print('Excel:\n$excel\n');
  print('CSV:\n$csv\n');
}

void newUserLogic() {
  final customer = NewCustomers(
    user: NewUser(
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
    ),
  );

  customer.accept(PdfHandler());
  customer.accept(ExcelHandler());
  customer.accept(CsvHandler());
}

void minorUserLogic() {
  final customer = MinorCustomer(
    user: MinorAccountUser(
      age: 15,
      guardianId: 82882,
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
      guardianName: 'Inioluwa',
    ),
  );

  customer.accept(PdfHandler());
  customer.accept(ExcelHandler());
  customer.accept(CsvHandler());
}

void jointUserLogic() {
  final customer = JointCustomer(
    user: JointAccountUser(
      jointAccountId: 92,
      accountHoldersInfo: [
        'Oluwaseyi',
        'Aderonke',
        'Inioluwa',
        'Tiwaloluwa',
      ],
      accountBalance: 9200020202.22,
    ),
  );

  customer.accept(PdfHandler());
  customer.accept(ExcelHandler());
  customer.accept(CsvHandler());
}
</code></pre>
<p>The same customer object accepts any visitor with the same call. The type dispatch happens automatically through the accept method. There's no type checking anywhere in the calling code, and no if-else or switch. Just <code>customer.accept(handler)</code> and the right method fires.</p>
<p>Now think about what happens when you need to add an XML export. You create one new class, XmlHandler, implement the four visit methods, and that's it. You don't touch ExistingUser, NewUser, MinorAccountUser, JointAccountUser, or any of the existing handlers. The system is genuinely open for extension and closed for modification.</p>
<h2 id="heading-real-world-example-two-notification-system">Real World Example Two: Notification System</h2>
<p>Here we have the same four user types and the same pattern. But it's a different operation entirely.</p>
<p>Your platform needs to notify users about account events. But not every user type should be notified the same way.</p>
<p>Existing users get email and push notifications. New users only get email because they haven't fully set up their profile yet. Minor account users get SMS to their guardian's number. Joint account users get notified on all channels because multiple people share the account.</p>
<p>Without the Visitor pattern, this logic would spread across all four user models or collapse into one enormous function full of type checks. With Visitor, it lives in three focused classes.</p>
<h3 id="heading-the-notification-visitor-interface">The Notification Visitor Interface</h3>
<pre><code class="language-dart">abstract class NotificationVisitor {
  void visitExistingCustomer(ExistingUser user);
  void visitNewCustomer(NewUser user);
  void visitMinorCustomer(MinorAccountUser user);
  void visitJointCustomer(JointAccountUser user);
}
</code></pre>
<p>This visitor returns void because notifications are side effects. They send messages, they don't return values.</p>
<h3 id="heading-the-concrete-notification-visitors">The Concrete Notification Visitors</h3>
<pre><code class="language-dart">class EmailNotificationHandler implements NotificationVisitor {
  @override
  void visitExistingCustomer(ExistingUser user) {
    print('Sending email to existing customer: ${user.firstName}');
    // email service call with full account details
  }

  @override
  void visitNewCustomer(NewUser user) {
    print('Sending welcome email to new customer: ${user.firstName}');
    // welcome email with onboarding steps
  }

  @override
  void visitMinorCustomer(MinorAccountUser user) {
    print('Sending email to guardian: ${user.guardianName}');
    // email goes to guardian, not the minor
  }

  @override
  void visitJointCustomer(JointAccountUser user) {
    for (final holder in user.accountHoldersInfo) {
      print('Sending email to joint holder: $holder');
      // all account holders get notified
    }
  }
}

class SmsNotificationHandler implements NotificationVisitor {
  @override
  void visitExistingCustomer(ExistingUser user) {
    print('Sending SMS to existing customer: ${user.firstName}');
  }

  @override
  void visitNewCustomer(NewUser user) {
    // new users are not SMS-verified yet, skip
    print('New customer ${user.firstName} not SMS-eligible yet');
  }

  @override
  void visitMinorCustomer(MinorAccountUser user) {
    print('Sending SMS to guardian ${user.guardianName} for minor ${user.firstName}');
    // SMS goes to guardian's registered number
  }

  @override
  void visitJointCustomer(JointAccountUser user) {
    for (final holder in user.accountHoldersInfo) {
      print('Sending SMS to joint holder: $holder');
    }
  }
}

class PushNotificationHandler implements NotificationVisitor {
  @override
  void visitExistingCustomer(ExistingUser user) {
    print('Push notification to existing customer: ${user.firstName}');
  }

  @override
  void visitNewCustomer(NewUser user) {
    print('Push notification to new customer: ${user.firstName}');
  }

  @override
  void visitMinorCustomer(MinorAccountUser user) {
    // minors do not have the app installed yet, guardian gets push
    print('Push notification to guardian: ${user.guardianName}');
  }

  @override
  void visitJointCustomer(JointAccountUser user) {
    for (final holder in user.accountHoldersInfo) {
      print('Push notification to joint holder: $holder');
    }
  }
}
</code></pre>
<p>Each handler knows the specific rules for each user type. <code>SmsNotificationHandler</code> knows that new users aren't SMS-verified yet. <code>PushNotificationHandler</code> knows that minor account notifications go to the guardian. <code>EmailNotificationHandler</code> knows that joint account holders all need to be notified individually.</p>
<p>This business logic lives in exactly one place per notification channel. When the rules change (and they always change), you update one class.</p>
<h3 id="heading-using-the-notification-visitors">Using the Notification Visitors</h3>
<pre><code class="language-dart">void notifyExistingUser() {
  final customer = ExistingCustomers(
    user: ExistingUser(
      id: 10,
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
      lastPaymentDate: DateTime.now(),
      accountBalance: 7373773.39,
    ),
  );

  customer.accept(EmailNotificationHandler());
  customer.accept(SmsNotificationHandler());
  customer.accept(PushNotificationHandler());
}

void notifyMinorUser() {
  final customer = MinorCustomer(
    user: MinorAccountUser(
      age: 15,
      guardianId: 82882,
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
      guardianName: 'Inioluwa',
    ),
  );

  // all three channels fire, each with minor-specific rules
  customer.accept(EmailNotificationHandler());
  customer.accept(SmsNotificationHandler());
  customer.accept(PushNotificationHandler());
}

void notifyJointUser() {
  final customer = JointCustomer(
    user: JointAccountUser(
      jointAccountId: 92,
      accountHoldersInfo: [
        'Oluwaseyi',
        'Aderonke',
        'Inioluwa',
        'Tiwaloluwa',
      ],
      accountBalance: 9200020202.22,
    ),
  );

  customer.accept(EmailNotificationHandler());
  customer.accept(SmsNotificationHandler());
  customer.accept(PushNotificationHandler());
}
</code></pre>
<p>The calling code is identical regardless of the user type or the notification channel. The dispatch is automatic. The rules live inside the visitors.</p>
<p>When WhatsApp notifications become a requirement (and they will), you create one <code>WhatsAppNotificationHandler</code> class with four visit methods. Nothing else changes.</p>
<h2 id="heading-real-world-example-three-fee-calculation">Real World Example Three: Fee Calculation</h2>
<p>Again, we have the same four user types and the same pattern. And once again, we have a completely different operation.</p>
<p>Your platform needs to calculate monthly maintenance fees. But each user type has different rules.</p>
<p>Existing customers pay a flat monthly fee based on their account balance. New customers are fee-exempt for their first three months. Minor account holders pay a reduced fee because their accounts have restricted features. Joint account holders have their fee split equally across all account holders.</p>
<p>Without Visitor, this logic ends up as a giant method somewhere with four branches, or worse, it leaks into the user models themselves. With Visitor, it lives in one focused class.</p>
<h3 id="heading-the-fee-visitor-interface">The Fee Visitor Interface</h3>
<pre><code class="language-dart">abstract class FeeVisitor {
  double visitExistingCustomer(ExistingUser user);
  double visitNewCustomer(NewUser user);
  double visitMinorCustomer(MinorAccountUser user);
  double visitJointCustomer(JointAccountUser user);
}
</code></pre>
<p>This visitor returns a double because fee calculation produces a numeric value.</p>
<h3 id="heading-the-concrete-fee-visitor">The Concrete Fee Visitor</h3>
<pre><code class="language-dart">class MonthlyFeeCalculator implements FeeVisitor {
  @override
  double visitExistingCustomer(ExistingUser user) {
    // 0.5% of account balance, minimum 500, maximum 5000
    final fee = user.accountBalance * 0.005;
    return fee.clamp(500, 5000).toDouble();
  }

  @override
  double visitNewCustomer(NewUser user) {
    // new customers are fee-exempt for the first 3 months
    return 0.0;
  }

  @override
  double visitMinorCustomer(MinorAccountUser user) {
    // flat reduced fee for minor accounts
    return 150.0;
  }

  @override
  double visitJointCustomer(JointAccountUser user) {
    // standard fee split equally across all holders
    const standardFee = 2000.0;
    return standardFee / user.accountHoldersInfo.length;
  }
}
</code></pre>
<p>Every fee rule for every user type lives in this one class. When the fee structure changes for existing customers, you touch one method in one class. When minor account fees are updated, same thing. None of the user models change, and no other visitor changes.</p>
<h3 id="heading-using-the-fee-visitor">Using the Fee Visitor</h3>
<pre><code class="language-dart">void calculateFees() {
  final existingCustomer = ExistingCustomers(
    user: ExistingUser(
      id: 10,
      firstName: 'Oluwaseyi',
      lastName: 'Fatunmole',
      lastPaymentDate: DateTime.now(),
      accountBalance: 7373773.39,
    ),
  );

  final newCustomer = NewCustomers(
    user: NewUser(
      firstName: 'Aderonke',
      lastName: 'Fatunmole',
    ),
  );

  final minorCustomer = MinorCustomer(
    user: MinorAccountUser(
      age: 15,
      guardianId: 82882,
      firstName: 'Inioluwa',
      lastName: 'Fatunmole',
      guardianName: 'Oluwaseyi',
    ),
  );

  final jointCustomer = JointCustomer(
    user: JointAccountUser(
      jointAccountId: 92,
      accountHoldersInfo: [
        'Oluwaseyi',
        'Aderonke',
        'Inioluwa',
        'Tiwaloluwa',
      ],
      accountBalance: 9200020202.22,
    ),
  );

  final calculator = MonthlyFeeCalculator();

  final existingFee = existingCustomer.accept(calculator);
  final newFee = newCustomer.accept(calculator);
  final minorFee = minorCustomer.accept(calculator);
  final jointFee = jointCustomer.accept(calculator);

  print('Existing customer fee: NGN $existingFee');
  print('New customer fee: NGN $newFee');
  print('Minor account fee: NGN $minorFee');
  print('Joint account fee per holder: NGN $jointFee');
}
</code></pre>
<p>The output:</p>
<pre><code class="language-plaintext">Existing customer fee: NGN 5000.0
New customer fee: NGN 0.0
Minor account fee: NGN 150.0
Joint account fee per holder: NGN 500.0
</code></pre>
<p>When a <code>PremiumFeeCalculator</code> is needed for a new tier of customers, you create one new class that implements <code>FeeVisitor</code>. The user models stay exactly as they are. The <code>MonthlyFeeCalculator</code> stays exactly as it is. The accept methods on all four consumers stay exactly as they are.</p>
<h2 id="heading-the-power-of-combining-all-three-operations">The Power of Combining All Three Operations</h2>
<p>Here's what makes the Visitor pattern truly shine in a system like this. You have the same four user types, and you can run any combination of visitors on any of them in the same call chain.</p>
<pre><code class="language-dart">void processUser(UserConsumer customer) {
  final pdf = customer.accept(PdfHandler());
  final csv = customer.accept(CsvHandler());

  customer.accept(EmailNotificationHandler());
  customer.accept(PushNotificationHandler());

  final fee = customer.accept(MonthlyFeeCalculator());

  print('Fee: NGN $fee');
  print('Documents generated and notifications sent');
}
</code></pre>
<p>One function, any user type, any combination of operations. The consumer doesn't care which visitors it receives. The visitors don't care which consumers call them. They speak to each other through the interface, and the interface guarantees everything works correctly.</p>
<p>We have three completely different operations (document export, notifications, and fee calculation) all applied to the same object with the same call pattern. None of these operations know about each other. None of them touch the user models. Each one lives in its own focused class with its own single reason to change.</p>
<h2 id="heading-when-to-use-the-visitor-pattern">When to Use the Visitor Pattern</h2>
<p>Use Visitor when you have a stable set of object types and a growing set of operations on them.</p>
<p>The pattern shines when the object hierarchy is unlikely to change frequently. It's optimized for adding new operations, not new types. Adding a new user type means updating every existing visitor. If your object types change constantly, Visitor creates more work than it saves.</p>
<p>It's also very effective when you need to perform multiple unrelated operations on a family of objects without polluting their classes with that logic. Document export, notification handling, fee calculation, and KYC validation are all unrelated operations. Each belongs in its own visitor, not scattered across the user models.</p>
<p>Visitor also works well when you want clean separation between data and behavior. The models hold data and the visitors define behavior. This makes both easier to understand, easier to test, and easier to maintain independently.</p>
<h2 id="heading-when-not-to-use-it">When Not to Use It</h2>
<p>Avoid Visitor when the object hierarchy changes frequently. Every time you add a new type, you must update every existing visitor. In a system where new user types appear regularly, this becomes painful quickly.</p>
<p>It's also not helpful when you only have one or two operations. For simple cases, the overhead of creating visitor interfaces, consumer interfaces, and multiple classes is not worth the benefit.</p>
<p>And avoid it when the operations are tightly coupled to the object's internal state in ways that make sense to keep together. Some behavior naturally belongs on the object itself.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The Visitor Design Pattern solves a problem that most developers only recognize after they've already made a mess of it. You have a family of objects with different types and different data. Operations come in one after another. Without a deliberate structure, those operations spread everywhere: into the models, utility classes, and massive switch statements that nobody wants to touch.</p>
<p>Visitor collects each operation into one focused class. The models stay clean and the operations stay isolated. Adding a new operation means creating one new class. The existing code doesn't change.</p>
<p>In the fintech examples above, we have three entirely different concerns: document export, notifications, and fee calculation. All are handled by handled by focused classes, none of which know anything about each other. The user models don't know about PDF or email or fees. The PdfHandler doesn't know about SMS. The MonthlyFeeCalculator doesn't know about push notifications. Each class has exactly one reason to exist and exactly one reason to change.</p>
<p>That s what a well-applied Visitor pattern looks like in practice. Clean, focused, and genuinely extensible.</p>
<p>Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Improve Your Phone’s Privacy ]]>
                </title>
                <description>
                    <![CDATA[ We use our phones for everything  –  texting, banking, browsing, tracking our health, even unlocking our homes. But with all that convenience comes a lot of risk. Apps are hungry for your data. Hackers are always looking for cracks in your security. ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-improve-your-phones-privacy/</link>
                <guid isPermaLink="false">684c50b9c6ec6bf605276b54</guid>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ privacy ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Fri, 13 Jun 2025 16:24:25 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749831817564/98cdcb42-6e7f-49c3-9a7c-49e8db78fc3f.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>We use our phones for everything  –  texting, banking, browsing, tracking our health, even unlocking our homes. But with all that convenience comes a lot of risk.</p>
<p>Apps are hungry for your data. Hackers are always looking for cracks in your security. And sometimes, we accidentally give away more than we realize.</p>
<p>The good news is you don’t need to be an expert to tighten things up. </p>
<p>Here are seven simple changes that can seriously improve your phone’s privacy. Each one takes just a few minutes, and together, they make your phone much harder to track, hack, or snoop on.</p>
<h2 id="heading-control-what-tracks-your-location"><strong>Control What Tracks Your Location</strong></h2>
<p>Let’s start with location tracking. </p>
<p>Most people don’t realize how many apps can access their exact whereabouts. Even seemingly harmless apps like weather or games may collect this info in the background. </p>
<p>Some use it to target ads, others sell it to data brokers, and a few could open doors to more serious threats, like someone building a full profile of your movements.</p>
<p>To reduce the risk, go into your phone’s settings and <a target="_blank" href="https://www.avg.com/en/signal/prevent-your-phone-being-tracked">check which apps can access your location</a>. Both iPhone and Android let you limit access to “While Using” the app, instead of “Always.” This way, apps can’t track you silently in the background. </p>
<p>Also, turn off “Precise Location” for apps that don’t need it. Your phone will still know your city, but it won’t pinpoint your exact house. This one tweak keeps dozens of apps from silently tracking your every move.</p>
<h2 id="heading-make-your-passcode-stronger"><strong>Make Your Passcode Stronger</strong></h2>
<p>Next up is your passcode. It’s your phone’s first line of defense, but far too many people still use weak ones  –  like birthdays, 123456, or just swiping a simple pattern. </p>
<p>If someone grabs your phone, a weak passcode makes it much easier for them to get in, especially if they’ve watched you unlock it a few times.</p>
<p>Switch to at least a six-digit PIN or, even better, an alphanumeric passcode with letters and numbers. Yes, it takes a second longer to type, but it’s far harder to guess. </p>
<p>And if your phone supports it, use your fingerprint for unlocking instead of facial recognition. Face unlock can sometimes be fooled by photos or similar faces, while fingerprints are generally more secure.</p>
<p>You should also consider enabling a setting that erases your data after multiple failed login attempts. This way, if your phone falls into the wrong hands, it won’t just be sitting there, waiting to be cracked.</p>
<h2 id="heading-cut-back-unnecessary-app-permissions"><strong>Cut Back Unnecessary App Permissions</strong></h2>
<p>Many apps ask for permissions they don’t really need. </p>
<p>A flashlight app that wants access to your contacts? A calendar app asking for microphone access? These are red flags. </p>
<p>The more permissions you grant, the more ways your data can leak  –  sometimes to advertisers, other times to third parties you’ve never heard of.</p>
<p>Go through your app permissions and turn off access that doesn’t make sense. Does that casual game really need your location? Does a recipe app need to see your photos? Probably not. This isn’t just about avoiding creepy behavior  –  it’s about reducing the number of ways bad actors can exploit your phone if something goes wrong.</p>
<p>Some malicious apps have been caught using these permissions to record audio, access files, or even track your activity across other apps. A regular permissions check-up can help stop that from happening.</p>
<h2 id="heading-switch-to-esim-for-better-security"><strong>Switch to eSIM for Better Security</strong></h2>
<p>One of the most overlooked privacy upgrades is switching to an <a target="_blank" href="https://saily.com/what-is-esim/">eSIM card</a>. That’s a digital SIM card built into your phone, and it offers real advantages over traditional physical SIM cards. The biggest one is security.</p>
<p>Physical SIM cards can be switched out easily if someone steals your phone. There’s also the risk of SIM swapping  –  where attackers convince your carrier to transfer your number to a different SIM, giving them control of your calls, texts, and even two-factor authentication codes. </p>
<p>With an eSIM, there’s no physical card to remove, and activating or transferring it requires extra authentication through your carrier.</p>
<p>If your phone supports eSIM – and most modern iPhones, Pixels, and Galaxy devices do –  you can switch by contacting your mobile carrier or using their app. </p>
<p>Once your eSIM is set up, consider removing the physical SIM entirely. It’s one less way someone can try to hijack your phone number.</p>
<h2 id="heading-dont-leave-bluetooth-and-wifi-open"><strong>Don’t Leave Bluetooth and Wi‑Fi Open</strong></h2>
<p>You might not think twice about leaving Bluetooth or Wi-Fi turned on, but doing so can leave your phone exposed. </p>
<p>Even when you’re not actively connected, your phone continues to look for known networks or nearby devices. This “sniffing” can give away your location, expose your device to tracking, or even let attackers try to exploit unpatched vulnerabilities.</p>
<p>For instance, there have been real-world attacks like <a target="_blank" href="https://en.wikipedia.org/wiki/BlueBorne_%28security_vulnerability%29">BlueBorne</a>, which let hackers take over phones just by being nearby with Bluetooth turned on. </p>
<p>Another risk is “Wi-Fi spoofing” –  when someone sets up a fake public network to trick your phone into connecting, giving them access to your traffic.</p>
<p>To protect yourself, get into the habit of turning off Wi-Fi and Bluetooth when you’re not using them. You’ll save battery, too. </p>
<p>If you’re connecting to public networks, avoid auto-connect settings and tell your phone to “forget” the network afterward. This keeps it from reconnecting without your knowledge later.</p>
<h2 id="heading-use-encrypted-messaging-apps"><strong>Use Encrypted Messaging Apps</strong></h2>
<p>Plain old text messages are easy to intercept. Phone carriers can access them, and if someone manages to snoop on your network, they can read your texts without much effort. That’s why encrypted messaging apps matter.</p>
<p><a target="_blank" href="https://signal.org/#signal">Signal</a> is one of the best options out there. It uses end-to-end encryption, which means only you and the person you’re chatting with can read your messages. Not even the app company can see them. It’s also open-source, which means experts can inspect the code for flaws.</p>
<p>WhatsApp also uses strong encryption, but it’s owned by Meta (formerly Facebook), which has a spottier track record when it comes to data privacy. </p>
<p>If you’re serious about protecting private conversations  –  especially with family, coworkers, or anyone handling sensitive info  – make the switch to an encrypted app.</p>
<h2 id="heading-keep-your-software-updated"><strong>Keep Your Software Updated</strong></h2>
<p>The last one is simple, but often ignored: keep your phone and apps updated. Every update includes security patches that fix known issues. </p>
<p>Hackers and malware often target devices running old software because those bugs are public knowledge by the time they strike. If your phone isn’t set to update automatically, change that now. </p>
<p>Also check your app updates regularly. Some apps introduce new permissions or bugs, so keeping everything current helps close those holes before they can be used against you.</p>
<p>Phones with outdated operating systems are more vulnerable to spyware, data theft, and unauthorized access. So even if you’re not excited about the new features, updates are your silent protectors behind the scenes.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>None of these steps will make you invisible –  but they will make your phone a lot harder to compromise. That’s the goal. Privacy isn’t about locking everything down forever. It’s about knowing what you’re sharing, and taking steps to control it.</p>
<p>Hope you enjoyed this article. You can <a target="_blank" href="https://manishshivanandhan.com/">learn more about me</a> or <a target="_blank" href="https://www.linkedin.com/in/manishmshiva/">connect with me on Linkedidn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The freeCodeCamp Mobile App – Learn to Code Right On Your Phone ]]>
                </title>
                <description>
                    <![CDATA[ I am happy to announce that the freeCodeCamp mobile app is finally ready for you to download. 🎊 The mobile development team just pushed a big update with many helpful improvements, including the much-awaited /learn user experience. You can now code ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/freecodecamp-mobile-app-curriculum-update/</link>
                <guid isPermaLink="false">66adef131ecaa5001d700509</guid>
                
                    <category>
                        <![CDATA[ freeCodeCamp Curriculum ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Android ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sem Bauke ]]>
                </dc:creator>
                <pubDate>Wed, 22 Mar 2023 12:23:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/michal-soukup-hDOskFirs-c-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I am happy to announce that the freeCodeCamp mobile app is finally ready for you to download. 🎊</p>
<p>The mobile development team just pushed a big update with many helpful improvements, including the much-awaited /learn user experience.</p>
<p>You can now code your way through the Responsive Web Design curriculum and save your progress – right on your phone. You can seamlessly shift your freeCodeCamp learning from your desktop to your phone at any time.</p>
<p>And we're working on implementing even more certifications, including our JavaScript Algorithms and Data Structures certification.</p>
<p>The /learn experience features a built-in code editor specifically designed for easy coding on the go. You can also use it to build your certification projects.</p>
<p>Here's a sneak peek into the /learn experience on a mobile device:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-17-at-09.12.10.png" alt="Image" width="600" height="400" loading="lazy">
<em>A view of the instructions pane telling the user how to complete the challenge</em></p>
<p>It's also possible to preview your challenges and projects. This shows a preview of the Camper Café project:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/Screenshot-2022-11-17-at-09.20.16.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Of course, there are so many more tutorials and features to explore in the mobile app. But we'll leave those for you to discover. 😉</p>
<p>We've also made some improvements to /news, Code Radio, and our Podcast listener – which are also available in the app.</p>
<h2 id="heading-how-can-i-download-the-app">How can I download the app?</h2>
<p>You can <a target="_blank" href="https://play.google.com/store/apps/details?id=org.freecodecamp">visit the Play Store page</a> and download the official freeCodeCamp app.</p>
<p>If you are not able to access the Google Play Store in your country, you can download the latest version of the .apk file directly <a target="_blank" href="https://github.com/freeCodeCamp/mobile/releases/latest">from GitHub</a>.</p>
<p>Many of the reviews of the app are of the old 2021 version, which was just a simple web app version that had lots of bugs. </p>
<p>This new version is the result of thousands of hours of development by the freeCodeCamp engineering team. We are very proud of this powerful Flutter-based Android app.</p>
<p>So after you use it for a while, if you like it and find it to be helpful, be sure to leave a 5-star review. 😉</p>
<h2 id="heading-how-can-i-help-the-freecodecamp-community-beta-test-upcoming-features">How can I help the freeCodeCamp community beta test upcoming features?</h2>
<p>Here's how to sign up for the open beta on Android. (We're working on getting the iOS version live soon, too.)</p>
<p>First, <a target="_blank" href="https://play.google.com/store/apps/details?id=org.freecodecamp">visit the Google Play Store page</a>.</p>
<p>At the bottom of the page, there should be a message saying "Join the beta." Just click join, and the app page should show you an update button shortly afterward.</p>
<p>That's it – you are now officially in the beta program. 🧑‍💻</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-88.png" alt="Image" width="600" height="400" loading="lazy">
<em>You may see this message in the Google Play Store.</em></p>
<p>Do note that your progress will not yet be saved on freeCodeCamp's servers. It will only be stored locally on your device. This means that any progress you make will not count towards completing any projects on the freeCodeCamp website. But we're working hard to add this functionality ASAP.</p>
<p>Thank you to all the open source contributors who have helped develop the freeCodeCamp mobile app so far. We are just getting started.</p>
<p>If you are interested in contributing to the mobile app, you can learn a lot about Flutter development and User Experience while helping the community. I encourage you to <a target="_blank" href="https://contribute.freecodecamp.org/#/how-to-setup-freecodecamp-mobile-app-locally">start your contribution journey with this guide</a>.</p>
<p>Happy coding. 🙂</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Monitor Machine Learning Projects on Your Mobile Device📱 ]]>
                </title>
                <description>
                    <![CDATA[ By Rishit Dagli What if you could monitor your Colab, Kaggle, or AzureML Machine Learning projects on your mobile phone? You'd be able to check in on your models on the fly – even while taking a walk🚶.  If you are an ML developer, you know how train... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-monitor-ml-projects-on-mobile-devices/</link>
                <guid isPermaLink="false">66d460cb9208fb118cc6d008</guid>
                
                    <category>
                        <![CDATA[ Machine Learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 24 Aug 2021 19:20:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/08/Frame-4-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Rishit Dagli</p>
<p>What if you could monitor your Colab, Kaggle, or AzureML Machine Learning projects on your mobile phone? You'd be able to check in on your models on the fly – even while taking a walk🚶. </p>
<p>If you are an ML developer, you know how training models can easily take a long time. How cool would it be to monitor this from your mobile phones?</p>
<p>Well, you can do it – and in &lt;5 lines of code.</p>
<h2 id="heading-why-monitoring-your-models-remotely-helps">Why Monitoring Your Models Remotely Helps</h2>
<p>Before getting on with the tutorial and showing you how it works, let me briefly describe what you can do with <a target="_blank" href="https://github.com/Rishit-dagli/TF-Watcher">TF Watcher</a>, an open-source project we will use to monitor our ML jobs:</p>
<ul>
<li>Integrates seamlessly with your ML workflow, so you don't need to change any other code in your workflow to make it work</li>
<li>All your visualizations and dashboards are real-time</li>
<li>You probably want to share your live dashboard or a previously run dashboard with your colleagues, and this also allows you to create shareable links</li>
<li>It's a PWA which lets you monitor your models offline in a limited capacity</li>
<li>You also get precise control over when you want to log the metrics</li>
</ul>
<h2 id="heading-how-to-monitor-your-ml-projects-on-your-phone">How to Monitor Your ML Projects on Your Phone</h2>
<p>Let's now go through the tutorial of how to monitor your models on a mobile device with Google Colab. I'll show you how to use tool this in Google Colab, so anyone can try it out, but you can pretty much replicate this anywhere (even on your local machine).</p>
<p>Feel free to follow along with <a target="_blank" href="https://colab.research.google.com/github/Rishit-dagli/TF-Watcher/blob/main/docs/source/TF-Watcher-Quickstart.ipynb">this colab notebook</a>.</p>
<h3 id="heading-install-the-tf-watcher-python-package"><strong>Install the tf-watcher Python Package</strong></h3>
<p>To monitor your Machine Learning jobs on mobile devices, you need to install the <code>tf-watcher</code> Python package. This is an open-source Python package that I built, and you can find the source code in <a target="_blank" href="https://github.com/Rishit-dagli/TF-Watcher">this GitHub repo</a>. </p>
<p>To install the Python package from PyPI, run the following command in your notebook cell:</p>
<pre><code> !pip install tf-watcher
</code></pre><h3 id="heading-how-to-create-a-simple-model">How to Create a Simple Model</h3>
<p>For the purposes of this example, we will see how you can monitor a training job – but you can use this package to monitor your evaluation or prediction jobs too. You will soon also see how you can easily specify the metrics you want to monitor.</p>
<p>In this example, we’ll use the <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/keras/datasets/fashion_mnist">Fashion MNIST</a>, a simple dataset of 60,000 grayscale images of 10 fashion categories. We start by loading the dataset and then we'll do some simple preprocessing to further speed up our example.</p>
<p>However, you can use everything we talk about in this article in your more complex experiments.</p>
<p>Let's fetch the dataset:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tensorflow <span class="hljs-keyword">as</span> tf

<span class="hljs-comment"># Load example MNIST data and pre-process it</span>
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

x_train = x_train.reshape(<span class="hljs-number">-1</span>, <span class="hljs-number">784</span>).astype(<span class="hljs-string">"float32"</span>) / <span class="hljs-number">255.0</span>
x_test = x_test.reshape(<span class="hljs-number">-1</span>, <span class="hljs-number">784</span>).astype(<span class="hljs-string">"float32"</span>) / <span class="hljs-number">255.0</span>

<span class="hljs-comment"># Limit the data to 1000 samples to make it faster</span>
x_train = x_train[:<span class="hljs-number">1000</span>]
y_train = y_train[:<span class="hljs-number">1000</span>]
x_test = x_test[:<span class="hljs-number">1000</span>]
y_test = y_test[:<span class="hljs-number">1000</span>]
</code></pre>
<p>Now we'll create a simple neural network that just has a single <code>Dense</code> layer. I'll be showing you how to use this with the TensorFlow's Sequential API, but this works in the exact same way while using the Functional API or subclassed models, too.</p>
<pre><code class="lang-python"><span class="hljs-comment"># Define the Keras model</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_model</span>():</span>
    model = keras.Sequential()
    model.add(keras.layers.Dense(<span class="hljs-number">1</span>, input_dim=<span class="hljs-number">784</span>))
    model.compile(
        optimizer=keras.optimizers.RMSprop(learning_rate=<span class="hljs-number">0.1</span>),
        loss=<span class="hljs-string">"mean_squared_error"</span>,
        metrics=[<span class="hljs-string">"accuracy"</span>],
    )
    <span class="hljs-keyword">return</span> model
</code></pre>
<p>You might have noticed that while compiling our model, we also specified <code>metrics</code> which lets us specify which metrics we need to monitor. </p>
<p>Here I mention "accuracy" so I should be able to monitor accuracy on my mobile device. By default, we logged "loss" so in this case, we would be monitoring 2 metrics: loss and accuracy.</p>
<p>You can add as many metrics as you need. You can also use TensorFlow's <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/keras/metrics">built-in metrics</a> or add your own custom metric, too.</p>
<h3 id="heading-how-to-create-an-instance-of-a-callback-class">How to Create an Instance of a Callback Class</h3>
<p>You will now import TF Watcher and create an instance of one of its classes:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> tfwatcher

MonitorCallback = tfwatcher.callbacks.EpochEnd(schedule = <span class="hljs-number">1</span>)
</code></pre>
<p>In this example:</p>
<ul>
<li>We use the <code>EpochEnd</code> class from TF Watcher to specify that we are interested in operating in the epoch level. There are quite a few of these classes which you can use for your own needs – find out all about the other classes in <a target="_blank" href="https://rishit-dagli.github.io/TF-Watcher/">the documentation</a>. </li>
<li>We pass in <code>schedule</code> as 1 to monitor after every 1 epoch. You could pass in 3 instead (to monitor after every 3 epochs) or you could also pass in a list of the specific epoch numbers you want to monitor.</li>
</ul>
<p>When you run this piece of code, you should see something like this printed out:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-76.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unique ID for your session</em></p>
<p>This includes a unique 7 character ID for your session. Be sure to make a note of this ID as you will use it to monitor your model.</p>
<h2 id="heading-how-to-start-monitoring-your-model">How to Start Monitoring Your Model 🚀</h2>
<p>Now we will train the model we built and monitor the real-time metrics for training on a mobile device.</p>
<pre><code class="lang-python">model = get_model()

history = model.fit(
    x_train,
    y_train,
    batch_size=<span class="hljs-number">128</span>,
    epochs=<span class="hljs-number">100</span>,
    validation_split=<span class="hljs-number">0.5</span>,
    callbacks = [MonitorCallback]
)
</code></pre>
<p>In this piece of code, we start training our model for 100 epochs (should be pretty quick in this case). We also add the object we made in the earlier step as a <code>callback</code>. </p>
<p>If in your case you are monitoring the prediction instead of training, you would add <code>callbacks = [MonitorCallback]</code> in the predict method.</p>
<p>Once you run the above piece of code, you can start monitoring it from the web app from your mobile device. </p>
<p>Go to <a target="_blank" href="https://www.tfwatcher.tech/">https://www.tfwatcher.tech/</a> and enter the unique ID you created above. This is a PWA which means you can also install this on your mobile devices and use it as a native android app, too.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-80.png" alt="Image" width="600" height="400" loading="lazy">
<em>Install the web app</em></p>
<p>Once you add your session ID you should be able to see your logs progressing in real-time through the charts. Apart from the metrics, you should also be able to see the time it took for each epoch. In other cases this might be time taken for a batch, too.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/TF-Watcher--MLH-Recording.png" alt="Image" width="600" height="400" loading="lazy">
<em>The monitoring dashboard</em></p>
<h3 id="heading-how-to-share-dashboards">How to Share Dashboards</h3>
<p>Since ML is highly collaborative, you might want to share your live dashboards with colleagues. To do so, just click the share link button and the app creates a shareable link for anyone to view your live progress or stored dashboards.</p>
<p><a target="_blank" href="https://www.tfwatcher.tech/logs/ybhzyxK">Here is the shareable link</a> for the dashboard I created in this tutorial.</p>
<h2 id="heading-what-else-can-you-do-with-tf-watcher">What Else Can You Do with TF Watcher?</h2>
<p>Though the example I just showed looked quite cool, there is a lot more we can do with this tool. Now I will briefly talk about two of those scenarios: Distributed Training and non-eager execution.</p>
<h3 id="heading-distributed-training">Distributed Training</h3>
<p>You might often distribute your Machine Learning training across multiple GPUs, multiple machines, or TPUs. You're probably doing this with the <code>[tf.distribute.Strategy](https://www.tensorflow.org/api_docs/python/tf/distribute/Strategy)</code> TensorFlow API. </p>
<p>You can use it in the exact same way with most distribution strategies with limited use while using <code>ParameterServer</code> in a custom training loop.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/08/image-79.png" alt="Image" width="600" height="400" loading="lazy">
<em>Distributed training</em></p>
<p>You can find some great examples of how to use these strategies with TensorFlow Keras <a target="_blank" href="https://www.tensorflow.org/guide/distributed_training#examples_and_tutorials">here</a>.</p>
<h3 id="heading-non-eager-execution">Non-eager execution</h3>
<p>In TensorFlow 2, eager execution is turned on by default. But you will often want to use <a target="_blank" href="https://www.tensorflow.org/api_docs/python/tf/function"><code>tf.function</code></a> to make graphs out of your programs. It's a transformation tool that creates Python-independent dataflow graphs out of your Python code.</p>
<p>One of the earliest versions of this project used some Numpy calls but guess what, you can now use the code in the same way in non-eager mode too.</p>
<h2 id="heading-thank-you-for-reading"><strong>Thank you for reading!</strong></h2>
<p>Thank you for sticking with me until the end. You can now monitor your Machine Learning projects from anywhere on your mobile device and take them to the next level. I hope you are as excited to start using this as I was.</p>
<p>If you learned something new or enjoyed reading this article, please share it so that others can see it. Until then, see you in the next post!</p>
<p>You can also find me on Twitter <a target="_blank" href="https://twitter.com/rishit_dagli">@rishit_dagli</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Native Communication Bridge in Flutter with WebView and JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ As a follow up to my article explaining how to create communication bridges in Android and iOS, I thought it might be a good idea to do the same for Flutter. While it may seem like this is a straightforward affair, you’ll soon realize it takes a bit ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-native-communication-bridge-in-flutter-with-webview-and-javascript/</link>
                <guid isPermaLink="false">66ba5008158e6c6a8cb8c79e</guid>
                
                    <category>
                        <![CDATA[ Flutter ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tomer ]]>
                </dc:creator>
                <pubDate>Tue, 01 Dec 2020 16:27:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/0_vBF65VQHbXyUUeHN.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a follow up to my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-build-cross-origin-communication-bridges-in-ios-and-andriod-7baef82b3f02/">article</a> explaining how to create communication bridges in Android and iOS, I thought it might be a good idea to do the same for Flutter.</p>
<p>While it may seem like this is a straightforward affair, you’ll soon realize it takes a bit of work to get this functionality working.</p>
<p>First and foremost, it is important to realize that (at the time of writing this article) Flutter does <strong>not</strong> have built in support for embedded WebViews.</p>
<p>Unlike a native application in either Kotlin or Swift where you can just instantiate a WebView component, you cannot add a WebView component to your Flutter application out of the box.</p>
<p>In this article, we'll go over how to configure WebView in Flutter applications, and how to communicate between Flutter and Webview.</p>
<h2 id="heading-how-to-configure-webview-in-a-flutter-application">How to configure WebView in a Flutter application</h2>
<p>After creating a new Flutter project, we need to use the <a target="_blank" href="https://pub.dev/packages/webview_flutter">webview_flutter package</a> to be able to use a WebView. We will add the dependency to our <code>pubspec.yaml</code> file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>  
       <span class="hljs-attr">flutter:</span>    
           <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
       <span class="hljs-attr">webview_flutter:</span> <span class="hljs-string">^1.0.7</span>
</code></pre>
<p>Then, we need to run <code>pub get</code> in the terminal:</p>
<pre><code class="lang-bash">flutter pub get
</code></pre>
<p>Next, we import the package in our <code>main.dart</code> file:</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'package:webview_flutter/webview_flutter.dart'</span>;
</code></pre>
<p>If you haven’t cleaned up the code from the starter project yet, now is a good time to do so. </p>
<p>After you remove all the comments, the floating action button and everything related to it, you will be left with this (I added a text widget just for show):</p>
<pre><code class="lang-dart"><span class="hljs-keyword">import</span> <span class="hljs-string">'dart:convert'</span>;

<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:webview_flutter/webview_flutter.dart'</span>;

<span class="hljs-keyword">void</span> main() {
  runApp(MyApp());
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyApp</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatelessWidget</span> </span>{
  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> MaterialApp(
      title: <span class="hljs-string">'Communication Bridge'</span>,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: <span class="hljs-string">'Native - JS Communication Bridge'</span>),
    );
  }
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyHomePage</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">StatefulWidget</span> </span>{
  MyHomePage({Key key, <span class="hljs-keyword">this</span>.title}) : <span class="hljs-keyword">super</span>(key: key);

  <span class="hljs-keyword">final</span> <span class="hljs-built_in">String</span> title;

  <span class="hljs-meta">@override</span>
  _MyHomePageState createState() =&gt; _MyHomePageState();
}

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Text(
      <span class="hljs-string">"Flutter JS-Native Communication Bridge"</span>
    );
  }
}
</code></pre>
<p>Which will give you this result:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_txc-SxRUBZFMR4mdJq-tCA.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-creating-a-local-html-asset">Creating a local HTML asset</h3>
<p>Since we will be using a local HTML file with embedded JavaScript code inside of it, we need to create it in our project. </p>
<p>All local assets in a Flutter application need to be in an <code>assets</code> directory. </p>
<p>Create an <code>assets</code> directory in your main project hierarchy by right clicking in the left side panel and choosing New → Directory:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_xlBwiAWJUdKiZWDsAdx7SQ.png" alt="Image" width="600" height="400" loading="lazy">
<em>The file hierarchy after creating the asses directory</em></p>
<p>Then, go on ahead and create <code>index.html</code> inside the assets directory and add the following code:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>My Local HTML File<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"title"</span>&gt;</span>Hello World!<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
            <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">fromFlutter</span>(<span class="hljs-params">newTitle</span>) </span>{
                <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"title"</span>).innerHTML = newTitle;
                sendBack();
             }

             <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendBack</span>(<span class="hljs-params"></span>) </span>{
                messageHandler.postMessage(<span class="hljs-string">"Hello from JS"</span>);
             }
        </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>You will notice that we have written two methods in the JavaScript section of our html:</p>
<ol>
<li><code>fromFlutter</code> is the method we will call from Flutter with a string representing the new title for the page</li>
<li><code>sendBack</code> is the method we will call to communicate back to Flutter. In it we are sending a string message.</li>
</ol>
<p>We will get into the contents of sendBack in a minute, but before that, we have to set up our WebView in our application.</p>
<p>✋ Don’t forget to add <code>index.html</code> to your <code>pubspec.yaml</code> under an <code>assets</code> section (use the correct indentation):</p>
<pre><code class="lang-yaml"><span class="hljs-attr">dependencies:</span>
  <span class="hljs-attr">flutter:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>
  <span class="hljs-attr">webview_flutter:</span> <span class="hljs-string">^1.0.7</span>
  <span class="hljs-attr">cupertino_icons:</span> <span class="hljs-string">^1.0.0</span>

<span class="hljs-attr">dev_dependencies:</span>
  <span class="hljs-attr">flutter_test:</span>
    <span class="hljs-attr">sdk:</span> <span class="hljs-string">flutter</span>

<span class="hljs-attr">flutter:</span>
  <span class="hljs-attr">uses-material-design:</span> <span class="hljs-literal">true</span>

  <span class="hljs-attr">assets:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-string">assets/index.html</span>
</code></pre>
<h3 id="heading-set-up-the-webview">Set up the WebView</h3>
<p>Since we already imported the package into our <code>main.dart</code> file, we need to replace the Text widget with a WebView widget:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
    );
  }

  _loadHtmlFromAssets() <span class="hljs-keyword">async</span> {
    <span class="hljs-built_in">String</span> file = <span class="hljs-keyword">await</span> rootBundle.loadString(<span class="hljs-string">'assets/index.html'</span>);
    _controller.loadUrl(<span class="hljs-built_in">Uri</span>.dataFromString(
        file,
        mimeType: <span class="hljs-string">'text/html'</span>,
        encoding: Encoding.getByName(<span class="hljs-string">'utf-8'</span>)).toString());
  }

}
</code></pre>
<p>We wrapped our WebView with a Scaffold widget (we'll go over this more later in the article), but let’s focus on the different fields of the WebView widget seen above:</p>
<ul>
<li><code>initialUrl</code> is where we can define which URL the WebView points to. Here we decided to point it to nothing since we are going to load our local HTML file</li>
<li><code>onWebViewCreated</code> is a callback we get from the package once the WebView is created. Since we want to save the controller instance that we get from this callback, we have created a private member to store it to, <code>_controller</code></li>
</ul>
<p>You will also notice that we created a method called <code>_loadHtmlFromAssets</code>, which as is implied by its name, will load our local HTML file into the WebView.</p>
<p>Inside this method, we use our private WebViewController instance, <code>_controller</code>, and it’s exposed method <code>loadUrl</code> to load our local HTML file. Due to the logic in this method, its execution is asynchronous.</p>
<p>If we run our application, we will get the following:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_hE6jeEprGAW3YkVt0AiYrA.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-communicate-from-flutter-to-webview">How to communicate from Flutter to WebView</h2>
<p>Now let’s add some functionality to call the <code>fromFlutter</code> method we defined in our local HTML file. </p>
<p>To do that, we will be adding a Floating Action Button (or FAB) to our layout and connecting its <code>onPressed</code> method to call the <code>fromFlutter</code> method.</p>
<p>This is also the reason behind the usage of the Scaffold widget – so we can easily add a FAB:</p>
<pre><code class="lang-dart"><span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        javascriptMode: JavascriptMode.unrestricted,
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: <span class="hljs-keyword">const</span> Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript(<span class="hljs-string">'fromFlutter("From Flutter")'</span>);
        },
      ),
    );
  }
</code></pre>
<p>In order to make calls from Flutter to our loaded HTML we are using the <code>evaluateJavascript</code> method. To be able to use it, we must add another property to our WebView called <code>javascriptMode</code>. </p>
<p>In the code above, we are setting it to unrestricted. If we don’t set it, we will not be able to communicate between Flutter and the WebView:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_odgcLrPQUlhGHdbaF4rO4A.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-communicate-back-from-webview-to-flutter">How to communicate back from WebView to Flutter</h2>
<p>Remember how I said we will talk about the contents of our <code>sendBack</code> method? Let's do that now:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">sendBack</span>(<span class="hljs-params"></span>) </span>{
  messageHandler.postMessage(<span class="hljs-string">"Hello from JS"</span>);
}
</code></pre>
<p>In the <code>sendBack</code> method, we are using an object called <code>messageHandler</code>, and it’s attached method called <code>postMessage</code>. </p>
<p>Just like creating a communication bridge in a native application, once you set one up, you are adding an object to the global <code>Window</code> object in the JavaScript layer to be used for communication.</p>
<p>You can name this object to whatever you like as long as you reference it when you make calls from JavaScript to your native application.</p>
<p>How is this object added to the JavaScript layer in our application, you might ask? By adding the <code>JavascriptChannels</code> attribute to our WebView widget:</p>
<pre><code class="lang-dart"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">_MyHomePageState</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">State</span>&lt;<span class="hljs-title">MyHomePage</span>&gt; </span>{

  WebViewController _controller;
  <span class="hljs-keyword">final</span> GlobalKey&lt;ScaffoldState&gt; _scaffoldKey = <span class="hljs-keyword">new</span> GlobalKey&lt;ScaffoldState&gt;();

  <span class="hljs-meta">@override</span>
  Widget build(BuildContext context) {
    <span class="hljs-keyword">return</span> Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(title: Text(<span class="hljs-string">'Webview'</span>)),
      body: WebView(
        initialUrl: <span class="hljs-string">'about:blank'</span>,
        javascriptMode: JavascriptMode.unrestricted,
        javascriptChannels: <span class="hljs-built_in">Set</span>.from([
          JavascriptChannel(
              name: <span class="hljs-string">'messageHandler'</span>,
              onMessageReceived: (JavascriptMessage message) {
               _scaffoldKey.currentState.showSnackBar(
                  SnackBar(
                      content: Text(message)
                  )
                 );
              })
        ]),
        onWebViewCreated: (WebViewController webviewController) {
          _controller = webviewController;
          _loadHtmlFromAssets();
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: <span class="hljs-keyword">const</span> Icon(Icons.arrow_upward),
        onPressed: () {
          _controller.evaluateJavascript(<span class="hljs-string">'fromFlutter("From Flutter")'</span>);
        },
      ),
    );

  }
</code></pre>
<p>We have defined a <code>JavascriptChannel</code> with a name and an <code>onMessageReceived</code> handler. The name we have given this channel, <code>messageHandler</code>, is the name we are using to communicate from the local HTML file we loaded to our native layer.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/1_AGpwDR2o8Fh7Re_Cwtg7fA.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Great success</em></p>
<p>For the keen eyed, you probably noticed that a new private variable has been added, <code>_scaffoldKey</code>. This is because we needed to add a key to our Scaffold widget so we can display the snackbar.</p>
<p>You can get the source code for the application described in this article below:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/TomerPacific/MediumArticles/tree/master/flutter_communication_bridge">https://github.com/TomerPacific/MediumArticles/tree/master/flutter_communication_bridge</a></div>
<p>Two final points to be aware of:</p>
<ol>
<li><a target="_blank" href="https://github.com/flutter/flutter/issues/30358">The alert method is broken in the webview_flutter package</a></li>
<li>To use the package in iOS, you must add the following key to your <code>info.plist</code> file: <code>&lt;key&gt;io.flutter.embedded_views_preview&lt;/key&gt;&lt;string&gt;yes&lt;/string&gt;</code></li>
</ol>
<p>Here are some other sources you may find helpful if you want to learn more about Flutter and WebViews:</p>
<ul>
<li><a target="_blank" href="https://medium.com/flutter/the-power-of-webviews-in-flutter-a56234b57df2">The Power of WebViews In Flutter</a></li>
<li><a target="_blank" href="https://pub.dev/packages/webview_flutter">WebView_Flutter Package</a></li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Mobile App That Outsmarts the Competitors ]]>
                </title>
                <description>
                    <![CDATA[ By Emma Coffinet The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices. It’s safe to say that mobile has almost completely taken over the desktop. With the number of ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-a-mobile-app-that-outsmarts-the-competitors/</link>
                <guid isPermaLink="false">66d45e3e73634435aafcef72</guid>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 21 Jul 2020 12:54:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/image-31-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Emma Coffinet</p>
<p>The amount of time people spend on their mobile phones has increased over the years, and so has the number of people using mobile devices.</p>
<p>It’s safe to say that <a target="_blank" href="https://www.freecodecamp.org/news/the-best-linux-tutorials/">mobile</a> has almost completely taken over the desktop. With the number of users crossing over to mobile, it has become essential to create apps that can provide a seamless and engaging mobile experience.</p>
<p>For a business, there are plenty of ways in which an app can be helpful. Some of these include:</p>
<ul>
<li>Improving sales and revenue generation.</li>
<li>Building a community and increasing engagement by providing the audience with resources.</li>
<li>Improving employee communication with internal business apps.</li>
<li>Improving mobile marketing strategy and increasing brand awareness.</li>
</ul>
<p>Even though there are many positives to it, creating an app can be tedious and intimidating. It can also be costly, risky, and can take a lot of time.</p>
<p>But if you create the app well enough, it will be worth everything in the end. To create a smart mobile app that beats the competition, here are some tips.</p>
<h2 id="heading-define-the-app-objectives">Define the app objectives</h2>
<p>The first step before you even start creating a mobile app is defining your reasons and clearly stating the app’s objectives. </p>
<p>If you don’t have clarity about small details like this, it will affect your planning and app building. In the end, you are not likely to get what you want.</p>
<p>There are two things that you must try to satisfy with your app. First, the ideal goal of users, and second, the purpose of your business. </p>
<p>To determine these, you have to ask yourself specific questions:</p>
<ul>
<li>Which parts of your business do you need to improve?</li>
<li>How can an app help solve the problem?</li>
<li>What are the possible results that you might get?</li>
</ul>
<p>Some other areas of your business that you also have to consider are your budget, timeline, market research, and so on.</p>
<h2 id="heading-state-the-functions-and-features-of-the-app">State the functions and features of the app</h2>
<p>After stating the purpose and objectives of your app clearly, your next step would be to define the <a target="_blank" href="https://mindsea.com/how-to-build-a-mobile-app/">scope of your mobile app</a>. At this point, you start to determine what the app will look like and the features that it will have. </p>
<p>You need to be creative and make a list of necessary functionality and features to achieve your desired results.</p>
<p>Some features that you may include in your app are:</p>
<ul>
<li>eCommerce integrations</li>
<li>Social sharing</li>
<li>Chat</li>
<li>Push notifications</li>
<li>Forms</li>
<li>Contact form</li>
</ul>
<p>Write down all the valuable features and let this guide you through your app development process.</p>
<h2 id="heading-research-app-competition">Research app competition</h2>
<p>Although you already are sure of what you are building and what you need in your app, you might want to look at some of your most successful competitors. Consider what they are doing with their apps and how it is helping them reach similar goals.</p>
<p>Be sure not to look at just your local competition. Research some of the bigger companies in the same industry that reach out to a similar audience in your country or other parts of the world. With this, you can get inspired and get new ideas you can use in the market.</p>
<p>Some of the things that you have to consider are app layout, features, and functionalities. Look out for other things that stand out or things that you might be missing.</p>
<h2 id="heading-plan-the-ux-and-user-journey-of-the-mobile-app">Plan the UX and user journey of the mobile app</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/07/image-32.png" alt="Image" width="600" height="400" loading="lazy">
<em>UX of an App</em></p>
<p>The success of <a target="_blank" href="https://buildfire.com/how-to-create-a-mobile-app/">mobile apps</a> depends a lot on the User Experience of the app. You have to make sure that your app’s functions align with the users’ desires and expectations. You must plan your User Experience in advance.</p>
<p>If you don’t plan the app’s user experience, you will not have an idea of how complex the app is. You also will not realize how much time you need to invest in developing the app. In the end, you won’t have something tangible to present during user testing. </p>
<p>Make sure that the users have a low UX resistance with the app. The primary goal here is to ensure that they find the solution in the most efficient and intuitive way possible.</p>
<p>If you don’t take the time to plan the UX before you start to build correctly, your users will likely experience difficulty with their use of the app. Then you would need to spend more resources and time to fix things.</p>
<p>The significant difference between a successful app and an unsuccessful one is the user experience. Poor user experience can stem from making some avoidable mistakes when building the app. Some of the mistakes to avoid for good user experience are:</p>
<h3 id="heading-not-understanding-the-needs-of-the-user">Not understanding the needs of the user</h3>
<p>The very foundation for building a good app is understanding what users need. Having an understanding of your audience is crucial. You have to consider the users’ pain points, how your app is better than your competition, and the interface.</p>
<h3 id="heading-adding-too-many-features">Adding too many features</h3>
<p>If it's your first time <a target="_blank" href="https://www.google.com/url?sa=t&amp;source=web&amp;rct=j&amp;url=https://brainiuminfotech.com/blog/mobile-app-development-small-business-get-right/&amp;ved=2ahUKEwjw4MC04c3qAhWJSsAKHehNDVoQFjAKegQIAhAB&amp;usg=AOvVaw0nk8eCEnSAMUERPZjXcsu7">developing a mobile app</a>, you might be tempted to add a lot of features you think are cool. </p>
<p>But this actually relates to a poor user experience most of the time. These features can overwhelm users and make them ditch your app.</p>
<h3 id="heading-creating-poor-and-confusing-navigation">Creating poor and confusing navigation</h3>
<p>No matter how good the onboarding experience is, if users cannot find what they want easily, then your app is less useful. </p>
<p>Your app should have clear navigation that makes it easy for even first time users to do what they want. There are different types of navigation, so you have to choose what you think is the most intuitive for your app.</p>
<p>Other mistakes that you can make that lead to poor user experience are:</p>
<ul>
<li>Neglecting the experience of first-time users.</li>
<li>Overcrowding the user interface</li>
<li>Using jargon and terminology that users don’t understand.</li>
</ul>
<h2 id="heading-launch-the-app">Launch the app</h2>
<p>The last step to <a target="_blank" href="https://www.appypie.com/how-to-create-an-app">creating a mobile app</a> is to launch the app. Following the launch, you should be open to user feedback and improve the app with regular updates based on user experience.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>It takes a lot of time, effort, and resources to create a mobile app. So if you want to create one that outsmarts the competition, you have to do more. It takes a lot of effort, and we’ve highlighted some of the key things you should do in this article. </p>
<p>Whatever it takes, make sure to put the user experience first. Focus on satisfying them and solving their problems with the app, and you are already halfway there.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What I've Learned On My Journey As A Self-Taught Mobile Developer ]]>
                </title>
                <description>
                    <![CDATA[ By Dragos Ivanov In this post, I'll share my entire journey about how I became a professional mobile developer. I hope that reading about my experience will help you reflect on your present and your future, and will either help you start your career ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/reflections-on-my-journey-as-a-self-taught-mobile-developer/</link>
                <guid isPermaLink="false">66d45e3e246e57ac83a2c72d</guid>
                
                    <category>
                        <![CDATA[ Developer ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 10 Jul 2020 11:06:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/07/Self-Taught-Developer-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dragos Ivanov</p>
<p>In this post, I'll share my entire journey about how I became a professional mobile developer.</p>
<p>I hope that reading about my experience will help you reflect on your present and your future, and will either help you start your career as a developer or motivate you to move forward in achieving your goals.</p>
<h2 id="heading-my-university-degree-and-how-it-all-started">My university degree and how it all started</h2>
<p>I finished high school with a mathematics-informatics degree in a small town in Romania.</p>
<p>Like most of my friends, you had two choices in terms of cities to go to for university. I chose Bucharest, the capital of Romania.</p>
<p>I grew up thinking that university is a mandatory thing. That probably happens in most countries.</p>
<p>All our parents want it for us.</p>
<p>I never felt a desire to choose a specific degree. Sound familiar? Never saw myself working as something after I graduated.</p>
<p>In the end, I chose to go to an economics university in Bucharest. Again there were two options. One was considered a good university, and another where you would pay a lot of money just to get a degree.</p>
<p>I took some exams at the first one, without studying, to be honest. And obviously I did not pass. </p>
<p>I had to go with the second option.</p>
<p>Fast forward and I graduated from my economics university. But I graduated two years late. I never had a passion for economics and never saw myself working as a banker. I always thought I wanted to get the diploma, and that's it.</p>
<p>I never considered how much I paid for that useless degree, but I needed a diploma to be accepted by society, right?</p>
<p>I was a failure, with an economics degree, but no experience or knowledge. In the following years, with the help of my family, I managed to create two businesses that failed, too.</p>
<p>I will not discuss those in the story, but let's just say that I learned a lot. I also played online poker, and I was pretty good at it.</p>
<p>Seven years after graduating from high school I found myself with no job experience, no successful business, and no money.</p>
<p>I knew I had to take action, and I knew that all my dreams about having a successful business would not happen soon unless I had a backup plan.</p>
<p>That's when I thought: </p>
<p><em>What job can I get that will make me happy, pay me well, and allow me to have a good life at 30 - 40 years old, even if I never manage to create my own business?</em></p>
<p>The only answer that came to mind was programming. I had some prior experience in high school and built a few websites.</p>
<p>There was only one problem – I did not like mathematics in high school, and I always thought that I would not be able to learn professional programming without an excellent understanding of it.</p>
<p>I was wrong.</p>
<p>There are probably a lot of people like me, people who have the same thoughts and doubts. But all you have to do is take action and start learning.</p>
<h2 id="heading-learning-android-and-java">Learning Android and Java</h2>
<p>It was 2014 when I first started looking into the idea to learn to code.</p>
<p>First thing I did was to Google for some courses in Bucharest, and I found a company that invited me to their offices. I went there, and I remember they had a lovely furnished office with a lot of iMACs. I told myself, "That's what I need."</p>
<p>Ten minutes later I found that they were doing all their courses online and that it was more like an office to sell the course rather than do the course.</p>
<p>I don't remember the exact price, but it was around 1500 - 2000 USD. I didn't take it.</p>
<p>I let go of the idea for a few months, then 2015 came. New year, new plans, new life, you know?</p>
<p>I started to look into an in person course again, and found out that they were called bootcamps.</p>
<p>Discovered one in Bucharest and they were doing Java, and it only cost around 800 USD for four months. It would be a few hours a day with a teacher and other students.</p>
<p>Looking back, I think they were cheap for what they offered, but I think we were the second batch they had. </p>
<p>They were telling us all kinds of things about being hired after the bootcamp, but I did not care. </p>
<p>I wanted to learn to code, and I thought that I would manage to find a job quickly after just a few months. I was right, but it was not as easy as I thought.</p>
<p>The classes started. They always told us that it is not enough to do only lessons during our hours together.</p>
<p>I tried to listen. But at home, things never made sense. Programming was hard, and I often thought that I would not be able to finish the bootcamp.</p>
<p>I pushed myself harder and harder. It was one month into the courses when I found that we were going to learn Java with Android, but again, I did not care. I was falling in love with Eclipse and things happened on the screen as we coded.</p>
<p>Eclipse is an Integrated Development Environment that was originally used to develop for Android. Now we use Android Studio.</p>
<p>It was hard. Lesson after lesson I was trying to learn variables, classes, inheritance, encapsulation, for loops, and so on. </p>
<p>But I struggled. I didn't have a clear picture of how I could use all these in a bigger app. It did not make sense a lot of times.</p>
<p>If you just started programming and you feel the same, I want you to know that it's normal.</p>
<p>Our mentors always told us: "You do not have to know all these off top of your head. Just try to understand what they are and how you can use them."</p>
<p>They were right, but I found that out later. At that specific moment in time, it did not help.</p>
<p>One thing which I regret is that I did not do projects from the beginning. I always thought that I needed a teacher and that you cannot learn anything online on your own. I was lazy and again, wrong.</p>
<p>After four months, I managed to make my first "non-working" app. It was an app where students could rent rooms from other students or people.</p>
<p>I said "non-working" because it did not have any backend or any users. It was more like a demo app that was using some SQLite for storing data.</p>
<p>I was proud of it, because a few months before, I never imagined I could do it.</p>
<p>The bootcamp finished, and I don't think I ever spoke with anyone from their management again.</p>
<p>Not sure if they tried to get me a job, or maybe they thought I was not good enough for a career as a developer.</p>
<h2 id="heading-first-interviews-and-first-job-as-a-junior-android-developer">First interviews and first job as a Junior Android Developer</h2>
<p>I started interviewing, and I remember that my first one was for a Java role at a big international company located in Bucharest. (Hint: they have over 300,000 employees, and their revenue from 2019 was about 77 billion.)</p>
<p>I did not take the interview, but I think that the conversation was a good one. I probably wasn't hired because I didn't have any experience.</p>
<p>After that, it took me another month to get the next interview.</p>
<p>A friend I made in the bootcamp helped by recommending me. If he reads this post, I want to thank him.</p>
<p>The role was actually as an Android developer for a Romanian outsourcing company that had a contract with a telecom company.</p>
<p>I had two interviews with them, mostly technical questions, and I still remember when they called to offer the role.</p>
<p>The salary was small, but it did not matter.</p>
<p>I think I started the bootcamp at the end of May 2015, and I began my first role as Junior Android Developer in January 2016.</p>
<p>It was quite an achievement.</p>
<p>My manager assigned me a project, and then I started learning about version control and how to work Agile, and how to work in 2 weeks sprints.</p>
<p>If you've started learning programming or you want to start, I recommend three things.</p>
<ul>
<li>Start today (Optional if you already started)</li>
<li>Do as many projects as possible</li>
<li>Learn version control (Git, Bitbucket, or Gitlab) and push all your projects there.</li>
</ul>
<p>Maybe I will write another article about all these things.</p>
<p>During my time at that company, I met a lot of friendly and helpful people. I was probably annoying to a lot of them because, at the beginning, I was asking for a lot of help.</p>
<h2 id="heading-new-country-and-more-android-jobs">New country and more Android jobs</h2>
<p>9 Months later I decided that I wanted to move to London because I was getting a lot of messages from recruiters. Also I thought that it would be easier to further my career there, then return to Bucharest.</p>
<p>I was lucky that my sister lived there, and she was kind enough to let me live with her.</p>
<p>Even when I had recruiters promising me interviews and stuff like that, when I got there I had zero meetings.</p>
<p>I knew that it would not be easy, and I applied to a lot of jobs online.</p>
<p>After two weeks, I got an interview at a British Telecom services company. They had a small IT department, and their Android developer was leaving. They had internal Android CRMs apps, used by their employees, and they needed someone for maintenance and to develop new apps.</p>
<p>It was a one year contract, and the pay wasn't great (I found that out later), but again, I was happy.</p>
<p>I learned a ton in that year (on my own).</p>
<p>I learned Android specific technologies like:</p>
<ul>
<li>What's an architecture like Model-View-Presenter and how to use it in an app</li>
<li>How to do proper Unit Testing</li>
<li>The SOLID principles</li>
</ul>
<p>And so on.</p>
<p>I learned all that at work and in my free time. I was working, and in my spare time, I was building apps for myself.</p>
<p>To this day, all my apps (5 on Android) have more than 100k downloads, mostly organic, but only one of them made more than 2,000 USD.</p>
<p>I worked for the telecom company for precisely one year. I wanted to try something different thing in London and work with more Android developers.</p>
<p>It took me some time to understand that, as a software developer, you always have to do more than what you do at work. It's the same with doctors or lawyers. They regularly need to improve their knowledge to be better than others.</p>
<p>I felt ready to work on a more significant project, but I don't think I was skilled enough.</p>
<p>It did not discourage me, and I took an Android role at a global outsourcing company.</p>
<p>I was going to work for a big British bank in London.</p>
<p>I was scared initially, but it took me one month to feel like I was part of that project.</p>
<p>I did three interviews before I entered the project. </p>
<p>During my career, all the interviews I did had two or three steps.</p>
<p>The first one is usually with HR where they ask you things about your experience.</p>
<p>The second interview could be with technical questions, take-home assignments or technical questions with some algorithms.</p>
<p>The third interview might be with a tech lead or with a manager or again with someone from HR.   </p>
<p>I started working at the bank in a proper Scrum team. We were 4 Android devs, 4 iOS devs, a Project Manager, a Product Owner, 2-3 Quality Assurance Engineers, a Business Analyst, Copywriter, Designers. </p>
<p>All these people were developing a crucial part of the app. The project was massive.</p>
<p>Just in the development team there were more than 30 Android and more than 30 iOS developers.</p>
<p>I stayed at that role for one year, like with my previous job. The reason? I wanted to go back to Romania.</p>
<p>I was lucky enough to have only good colleagues around me. </p>
<p>It's never wrong to ask for help if you want to learn. We've all started from the beginning, with zero knowledge. I feel that it's terrible not to want to learn when you don't know.</p>
<p>The year at the bank taught me a lot, and it felt like a few years. I learned:</p>
<ul>
<li>How to do code reviews</li>
<li>How to work on a project that required 100% code coverage for Unit Testing</li>
<li>How to deliver features on time</li>
<li>What is clean architecture and how to write code that's easy to read without leaving a ton of comments</li>
</ul>
<p>And many more that I probably don't remember.</p>
<h2 id="heading-going-back-home-with-more-knowledge">Going back home with more knowledge</h2>
<p>It was November 2018 when I went back to Bucharest, after two years and a bit of living in London.</p>
<p>It was an excellent experience, but it did not feel like home.</p>
<p>I got a new job for another outsourcing Romanian company quite fast (2 weeks) after I came back. </p>
<p>It took me only four months to leave again for a new six months project in London.</p>
<p>I was not happy to leave my girlfriend alone, but the money was good for only six months of work.</p>
<p>I'm not allowed to disclose any information about the project because I signed a non-disclosure agreement, and today I'm still working for them. But I'm located in Bucharest right now. I've been working for the current company for more than a year and a half.</p>
<p>What did I learn on this project?</p>
<ul>
<li>How to create a team</li>
<li>How to start a big app from scratch. I will probably be very proud once we launch and people will use it.</li>
<li>How to adapt requirements with a lot of unknowns.</li>
<li>How to deliver by working with people all over the world.</li>
</ul>
<p>It's been a crazy journey.</p>
<h2 id="heading-conclusion-and-what-i-learned">Conclusion and what I learned</h2>
<p>My post is at over 2000 words, and I feel I did not give you a lot of details about what I learned. I only scratched the surface.</p>
<p>It was not easy, but I don't regret choosing this career.</p>
<p>If you are me from 5 years ago, just start. </p>
<p>You will feel like quitting. You will think that you are not smart enough, you will feel like any developer that takes a few hours/days to solve something without any luck and then has a moment of brilliance.</p>
<p>It's not wrong not to know, and no question is stupid. It's terrible if you don't want to learn.</p>
<p>Today, more developers than ever are willing to help. You can easily find Discord groups where people are happy to answer your programming questions. There are a lot of Reddit communities that will be helpful. Maybe even Slack channels can work for you. Finding a mentor can be a solution too.</p>
<p>Websites and YouTube channels like freeCodeCamp are all you need to get started.</p>
<p>Here are all the things I hope you learned in this post:</p>
<ul>
<li>Starting is hard, but every day of learning something new will give you enormous satisfaction.</li>
<li>You need to do all kinds of projects. Knowing the basics is good, but building things and working with version control will help you prepare for a future job.</li>
<li>People are willing to help (both online and future colleagues)</li>
<li>There will be days when nothing will work. You will not find a solution easily. Either relax and come back to the problem later or just ask for help.</li>
<li>All developers (junior, mid or senior) search for solutions on Google and get stuck frequently.</li>
<li>You will feel impostor syndrome, but trust me when I say that I met developers with CS degrees who are worse than me.</li>
<li>Being a developer it’s not only about coding. Soft skills are important too.</li>
</ul>
<p>If you liked this article and want more of this, please <a target="_blank" href="https://twitter.com/dragos_ivanov">follow me on Twitter</a>. I write about my journey as a mobile developer, my failed/successful start-ups, about app marketing, and all kinds of other things I learned in the past 10 years.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Develop Particle IoT Apps Using NativeScript ]]>
                </title>
                <description>
                    <![CDATA[ By Jared Wolff If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While there are easy ways, they're not for production use. In this tutorial, we'll talk about the basics of Particle app development. You'll ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-develop-particle-iot-apps-using-nativescript/</link>
                <guid isPermaLink="false">66d8504f29e30bc0ad47757b</guid>
                
                    <category>
                        <![CDATA[ iot ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ NativeScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ particle ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 27 Jan 2020 17:42:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/NativeScript---Particle.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jared Wolff</p>
<p>If you're developing any type of IoT product, inevitably you'll need some type of mobile app. While <a target="_blank" href="https://www.jaredwolff.com/create-a-cross-platform-app-using-blynk/">there are easy ways</a>, they're not for production use.</p>
<p>In this tutorial, we'll talk about the basics of Particle app development. You'll learn about some of the many app frameworks you can take advantage of. Plus there's libraries, tricks, and tools along the way to make your life a lot easier.</p>
<h2 id="heading-app-frameworks">App Frameworks</h2>
<p>Sometimes it's dang near irritating to program multiple applications natively. You see, Swift (or Objective C ?) and Java aren't terrible at first glance (well, maybe except for Obj-C ?). But when you're resource constrained, you have to figure out a new game plan. That's where App Frameworks come in.</p>
<p>These frameworks allow an app developer to write, build and test cross platform apps. In some cases, the frameworks convert your app into native code. That means that they run as fast and as well as one written in Swift or Java.</p>
<p>I did the research and as of January 2020, here are some of the most supported frameworks:</p>
<ul>
<li><a target="_blank" href="https://github.com/framework7io/framework7">Framework7</a></li>
<li><a target="_blank" href="https://flutter.dev/">Flutter</a></li>
<li><a target="_blank" href="https://www.nativescript.org/">NativeScript</a></li>
<li><a target="_blank" href="https://github.com/facebook/react-native">ReactNative</a></li>
<li><a target="_blank" href="https://github.com/ionic-team/ionic">Ionic</a></li>
<li><a target="_blank" href="https://cordova.apache.org/">Cordova</a> / <a target="_blank" href="https://phonegap.com/">PhoneGap</a></li>
<li><a target="_blank" href="https://github.com/meteor/meteor">Meteor</a></li>
<li><a target="_blank" href="https://dotnet.microsoft.com/apps/xamarin">Xamarin</a></li>
</ul>
<p>The list goes on for days.</p>
<p>I've used a few of these frameworks in the past. I've built a Meteor app which (surprisingly) worked. In the end I had to pick one though. What did I go with?</p>
<p><strong>NativeScript.</strong></p>
<p>For the most part, NativeScript's documentation and on-boarding experience is fantastic. Not only can you preview your app inside an emulator but you can load it directly to your phone too!</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" alt="images/Apple_iPhone_6s_Gold_-__status-b1ad9325-8e81-4ee0-b72a-687b62adec29.png" width="730" height="605" loading="lazy"></p>
<p>One of the cool things about NativeScript is that it supports TypeScript. TypeScript is a superset of JavaScript with some extra wiz-bang features. </p>
<p>Unlike other languages, JavaScript technically has no types. If you've done any Particle development you likely know what a type is. We're talking about <code>int</code>, <code>String</code>, <code>float</code> and more. i.e. they're directives to to make sure your JavaScript code stays consistent.</p>
<p>NativeScript is also compatible with most major JavaScript web frameworks. This includes <a target="_blank" href="https://vuejs.org/">Vue.Js</a> and <a target="_blank" href="https://angular.io/">Angular</a>.</p>
<p>I've only noticed one major drawback thus far: the mobile preview mode (<code>tns preview</code> command) does not pay well with native libraries. If you have some native platform specific libraries, you'll have to use the emulator or a device (if you have one).</p>
<p>If you're gung-ho and you <em>want</em> to build multiple apps in their respective languages, the more power to you. There is an advantage over the above frameworks: tried and true Particle SDKs.</p>
<h2 id="heading-available-libraries-amp-sdks">Available Libraries &amp; SDKs</h2>
<p>Particle has gone out of their way to make app development a little easier. This is thanks to the massive development work that has gone into their own SDKs. Yup, gone are the days you have to write manual HTTP request handlers.</p>
<p>Here's a link to both the iOS and Android SDKs:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android</a></li>
</ul>
<p>Though we won't be covering them here, they reflect all the potential calls that you can make using the <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Cloud API.</a></p>
<p>Speaking of Cloud API, Particle has also developed a <a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">Node.js</a> library as well. As you can imagine, you can use this for your server side code or JavaScript based app frameworks. Sadly, it doesn't work with NativeScript. Frameworks that use a <a target="_blank" href="https://www.tutorialspoint.com/android/android_webview_layout.htm">WebView</a> should be more compatible.</p>
<p>In the case of this tutorial, we'll be mostly focusing on the Cloud API. This way you have a good understanding of the overall system. It may seem intimidating but if you do it right, you'll get the hang of it real fast.</p>
<h2 id="heading-making-api-calls">Making API Calls</h2>
<p>In NativeScript you can't use libraries like <code>[request](https://github.com/request/request)</code>. (Which happens to be the library Particle's very own <a target="_blank" href="https://github.com/dmiddlecamp">DMC</a> used in the <a target="_blank" href="https://github.com/particle-iot/particle-cli">CLI</a> — DMC if you're reading this, Hi!) You'll have to use the provided <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http">HTTP</a> module. </p>
<p>If you scroll all the way to the <a target="_blank" href="https://docs.nativescript.org/ns-framework-modules/http#http-post">bottom of that page</a>, you'll see a fully fledged <code>POST</code> example. I'll reproduce it here but with some Particle specific changes:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"name"</span>, <span class="hljs-string">"update"</span>);
data.append(<span class="hljs-string">"data"</span>, <span class="hljs-string">"It's hammer time!"</span>);
data.append(<span class="hljs-string">"private"</span>, <span class="hljs-string">"true"</span>);
data.append(<span class="hljs-string">"access_token"</span>, _token);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/devices/events`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>The above is an example of what's equivalent to <code>Particle.publish</code> in DeviceOS. Let's break down the parts.</p>
<p>First of all, one of the main gotchas of Particle's Web API is the data format. I first expected that they use JSON but I was sorely wrong. After actually <em>reading</em> the documentation I realized that most POST requests were actually <code>application/x-www-form-urlencoded</code>. That means when you submit data, it's the equivalent to hitting the submit button on an HTML form.</p>
<p>Fortunately, there is an easy way to assemble form data in Node/JavaScript. We can use the <code>FormData()</code> object. Take a look at the above. There should be some familiar parameter names in the <code>data.append</code> calls.</p>
<p><code>"name"</code> refers to the name of the event you're publishing to.</p>
<p><code>"data"</code> refers to the string formatted data that you're publishing.</p>
<p><code>"private"</code> dictates whether or not you want to broadcast this data to the whole Particle world, or just your little corner of it.</p>
<p><code>"access_token"</code> is a token that you can generate in order to make these API calls. Without a token though, you're dead in the water.</p>
<h3 id="heading-getting-a-token">Getting a Token</h3>
<p>Where do we get this elusive <code>access_token</code>?</p>
<p>At first I had no idea.</p>
<p>I created an OAuth user and secret in the console. That lead to a dead end. Fiddled around with different API calls and settings. Nothing. Then it hit me like a ton of bricks. There's an <code>access_token</code> attached to the curl request on every device page!</p>
<p>Open up any device, click the little console button near <em>Events.</em> A popup with instructions an a URL will pop up. Copy the text after <code>access_token=</code>. That is your <code>access_token</code>! See below:</p>
<p><img src="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" alt="images/Screen_Shot_2020-01-25_at_8.55.21_AM.png" width="730" height="298" loading="lazy"></p>
<p>You can use this token to make calls to the Particle API. This can be to subscribe, publish, write to a function, read variables and more.</p>
<h3 id="heading-through-the-command-line">Through the command line</h3>
<p>That's nice and everything but how the heck can you <em>programmatically</em> generate one? One way is with the command line.</p>
<p><code>particle token create</code> is the name of the command you need to know about. When you run it, you'll be prompted to login. (Also enter your Authenticator code if you use one.) Then the command line will spit out a shiny new <code>access_token</code> you can use with the API!</p>
<h3 id="heading-through-the-api-itself">Through the API itself</h3>
<p>If you couldn't guess, <code>particle token create</code> is a <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/20d02afc7b72ade0e79d4f4ec724ec6cce9fff1b/src/lib/api-client.js#L192">frontend to a raw API call</a>. You can make these API calls directly too. Here's what it looks like in NativeScript.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Create form post data</span>
<span class="hljs-keyword">var</span> data = <span class="hljs-keyword">new</span> FormData();
data.append(<span class="hljs-string">"username"</span>, <span class="hljs-string">"jaredwolff"</span>);
data.append(<span class="hljs-string">"password"</span>, <span class="hljs-string">"this is not my password"</span>);
data.append(<span class="hljs-string">"grant_type"</span>, <span class="hljs-string">"password"</span>);
data.append(<span class="hljs-string">"client_name"</span>, <span class="hljs-string">"user"</span>);
data.append(<span class="hljs-string">"client_secret"</span>, <span class="hljs-string">"client_secret_here"</span>);

<span class="hljs-comment">// Configure the httpModule</span>
<span class="hljs-keyword">return</span> httpModule
    .request({
        url: <span class="hljs-string">`https://api.particle.io/v1/oauth/token`</span>,
        method: <span class="hljs-string">"POST"</span>,
        content: data
    })
    .then(
        <span class="hljs-function"><span class="hljs-params">response</span> =&gt;</span> {
            <span class="hljs-keyword">const</span> result = response.content.toJSON();
            <span class="hljs-built_in">console</span>.log(result);
        },
        <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
            <span class="hljs-keyword">if</span> (e) <span class="hljs-built_in">console</span>.log(e);
        }
    );
</code></pre>
<p>This call <em>may</em> get more complicated. Mostly in the case if you have two factor authorization setup. It's well worth it when you figure it all out. After all, no one wants to manually create auth tokens if they don't have to!</p>
<p>Now you're ready to write and read from your devices. There's one thing though that may trip you up. Subscribing to events can be troublesome with a regular HTTP client. So much so that if you try to do it with NativeScript's HTTP client, it will lock up and never return. Luckily there is a way to handle these special HTTP calls.</p>
<h2 id="heading-server-sent-what">Server Sent What?</h2>
<p>Server Sent Events (SSE for short) is an HTTP/S subscription functionality. It allows you to connect to a SSE end point and continuously listen for updates. It's a similar web technology to what companies use for push notifications. It does require some extra functionality under the hood though...</p>
<h3 id="heading-sse-library">SSE Library</h3>
<p>After much head scratching and searching I stumbled upon <code>nativescript-sse</code>. It looked simple enough that I could start using immediately. More problems arose when I tried to use it though.</p>
<p>First, it turns out you can't use the library in <code>tns preview</code> mode. The alternative is to use <code>tns run ios --emulator</code> or use <code>tns run ios</code> with your iPhone connected to your computer. The non-emulator command will automatically deliver your prototype app.</p>
<p><strong>Side note:</strong> I had already set up my phone in Xcode. You may have to do this yourself before <code>tns run ios</code> is able to find and deploy to your phone.</p>
<p>Secondly, once I got the library working, I noticed I would get some very nasty errors. The errors seemed to happen whenever a new message from Particle came along. </p>
<p>Turns out the underlying Swift library for iOS <a target="_blank" href="https://github.com/inaka/EventSource/issues/89">had fixed this last year.</a> So I took it upon myself to figure out how to upgrade the NativeScript plugin. I'll save you the time to say that it can be a pain and there is a learning curve!</p>
<p>Fortunately after some hacking I got something working. More instructions on how to compile the plugin are in the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse">README</a>. Alternatively, you can download a pre-built one on the <a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/releases/tag/v4.0.3">Release page of the repository.</a></p>
<p>Download the <code>.tgz</code> file to wherever you like. Then, you can add it using <code>tns plugin add</code>. The full command looks like this:</p>
<pre><code>tns plugin add path/to/plugin/file.tgz
</code></pre><p>You can check to make sure the library is installed by running <code>tns plugin list</code></p>
<pre><code>**jaredwolff$ tns plugin list
<span class="hljs-attr">Dependencies</span>:
┌─────────────────────┬──────────────────────────────────────────────────────────────────────────────────┐
│ Plugin              │ Version                                                                          │
│ @nativescript/theme │ ~<span class="hljs-number">2.2</span><span class="hljs-number">.1</span>                                                                           │
│ nativescript-sse    │ file:../../Downloads/nativescript-sse/publish/package/nativescript-sse<span class="hljs-number">-4.0</span><span class="hljs-number">.3</span>.tgz │
│ tns-core-modules    │ ~<span class="hljs-number">6.3</span><span class="hljs-number">.0</span>                                                                           │
└─────────────────────┴──────────────────────────────────────────────────────────────────────────────────┘
Dev Dependencies:
┌──────────────────────────┬─────────┐
│ Plugin                   │ Version │
│ nativescript-dev-webpack │ ~<span class="hljs-number">1.4</span><span class="hljs-number">.0</span>  │
│ typescript               │ ~<span class="hljs-number">3.5</span><span class="hljs-number">.3</span>  │
└──────────────────────────┴─────────┘
<span class="hljs-attr">NOTE</span>:
If you want to check the dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep dependencies
If you want to check the dev dependencies <span class="hljs-keyword">of</span> installed plugin use npm view &lt;pluginName&gt; grep devDependencies**
</code></pre><p>Once installed, invoking the library takes a few steps. Here's an example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { SSE } <span class="hljs-keyword">from</span> <span class="hljs-string">"nativescript-sse"</span>;

sse = <span class="hljs-keyword">new</span> SSE(
            <span class="hljs-string">"https://api.particle.io/v1/events/blob?access_token=&lt;your access token&gt;"</span>,
            {}

<span class="hljs-comment">// Add event listener</span>
sse.addEventListener(<span class="hljs-string">"blob"</span>);

<span class="hljs-comment">// Add callback</span>
sse.events.on(<span class="hljs-string">"onMessage"</span>, <span class="hljs-function"><span class="hljs-params">data</span>=&gt;</span>{
    <span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> do stuff with your event data here!</span>
    <span class="hljs-built_in">console</span>.log(data);
});

<span class="hljs-comment">// Connect if not already</span>
sse.connect();
</code></pre>
<p>First you need to import and create an instance of the library. When you create the instance, you will have to enter the URL that you want to use. </p>
<p>In this case we'll be doing the equivalent of <code>Particle.subscribe()</code>. It should look something similar to the above: <code>https://api.particle.io/v1/events/&lt;your event name&gt;?access_token=&lt;your access token&gt;</code>. </p>
<p>Replace <code>&lt;your event name&gt;</code> and <code>&lt;your access token&gt;</code> with the name of your event and your freshly created token!</p>
<p>Then you set up the library to listen for the event you care about. In this case <code>blob</code> is the event I most care about.</p>
<p>Then make sure you configure a callback! That way you can get access to the data when <code>blob</code> does come along. I've made a <code>TODO</code> note where you can access said data.</p>
<p>Finally, you can connect using the <code>.connect()</code> method. If you don't connect, SSE will not open a session and you'll get no data from Particle.</p>
<p>Placement of the code is up to you but from the examples it looks like within the <code>constructor()</code> of your model is a good place.(<a target="_blank" href="https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts">https://github.com/jaredwolff/nativescript-sse/blob/master/demo/app/main-view-model.ts</a>)</p>
<h3 id="heading-other-examples">Other Examples</h3>
<p>If you're curious how to use SSE in other places I have another great example: Particle's CLI.</p>
<p>Particle uses the <code>[request](https://github.com/request/request)</code> library to handle SSE events in the app. Whenever you call <code>particle subscribe blob</code> it invokes a <code>getStreamEvent</code> further inside the code.  You can <a target="_blank" href="https://github.com/particle-iot/particle-cli/blob/master/src/lib/api-client.js#L862">check it out here.</a> The <code>request</code> library has more information on streaming <a target="_blank" href="https://github.com/request/request#streaming">here</a>.</p>
<h2 id="heading-more-resources">More resources</h2>
<p>This is but the tip of the iceberg when it comes to connecting with Particle's API. Particle has some great documentation (as always) you can check out. Here are some important links:</p>
<ul>
<li><a target="_blank" href="https://docs.particle.io/reference/device-cloud/api/">API documentation</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/javascript/">Javascript SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/ios/">iOS SDK</a></li>
<li><a target="_blank" href="https://docs.particle.io/reference/SDKs/android/">Android SDK</a></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this post we've talked about app frameworks, NativeScript, NativeScript plugins and Server Sent Events. Plus all the Particle related things so you can connect your NativeScript app to Particle's API. </p>
<p>I hope you've found this quick tutorial useful. If you have any questions feel free to leave a comment or <a target="_blank" href="https://www.jaredwolff.com/contact/">send me a message</a>. Also be sure to check out my <a target="_blank" href="https://www.jaredwolff.com/the-ultimate-guide-to-particle-mesh/">newly released guide</a>. It has content just like this all about Particle's ecosystem.</p>
<p>Until next time!</p>
<p><strong>This post was originally from</strong> <a target="_blank" href="https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/"><strong>https://www.jaredwolff.com/how-to-develop-particle-iot-apps-using-nativescript/</strong></a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Progressive Web Apps vs Accelerated Mobile Pages: What's the Difference and Which is Best for You? ]]>
                </title>
                <description>
                    <![CDATA[ Do you understand what PWAs and AMPs are, and which might be better for you? Let's have a look and find out. So many people own smartphones these days. This opens up endless opportunities for a business - opportunities which, however, are immediately... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/pwa-vs-amp-what-is-the-difference-and-how-do-you-choose/</link>
                <guid isPermaLink="false">66be14ce2728aa32fea75a32</guid>
                
                    <category>
                        <![CDATA[ AMP ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ PWA ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Oleh Romanyuk ]]>
                </dc:creator>
                <pubDate>Tue, 07 Jan 2020 14:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/01/PWA-vs-AMP.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Do you understand what PWAs and AMPs are, and which might be better for you? Let's have a look and find out.</p>
<p>So many people own smartphones these days. This opens up endless opportunities for a business - opportunities which, however, are immediately challenged by the immense number of competitors in the mobile software market. </p>
<p>Mobile apps are surely more convenient than web or desktop platforms. Yet, they are not the most comfortable option that the industry offers.</p>
<p>To hit the highest level of user satisfaction and to outrun competitors, inventive people opt in favor of progressive web apps (PWAs) or accelerated mobile pages (AMPs).</p>
<p>What are these things, and how should you choose the best option? Let’s consider each one-by-one by going through these simple questions:</p>
<ol>
<li>What is a PWA?</li>
<li>What is an AMP?</li>
<li>How are they similar?</li>
<li>How are they different?</li>
<li>Why PWAs are better than web pages</li>
<li>Why PWAs are better than native mobile</li>
<li>Why AMPs are better than web pages</li>
<li>Why AMPs are NOT better than native mobile</li>
</ol>
<h2 id="heading-1-what-is-a-pwa">1. What Is a PWA?</h2>
<p>A progressive web application, or PWA, unites the advantages of both web and mobile apps into a single software product. As <a target="_blank" href="https://developers.google.com/web/progressive-web-apps">Google</a> declares, PWAs are “user experiences that have the reach of the web and are reliable, fast, and engaging”. It is a technology that lets you use a website as if it was a native app.</p>
<p><a target="_blank" href="https://twitter.com/?lang=en">Twitter</a> is one of the major companies using PWAs. To install the app, you open the web version on your phone and add it to your home screen. When you open Twitter from the home screen icon, you will be opening it as a progressive web app.</p>
<p><img src="https://images.ctfassets.net/6xhdtf1foerq/1TGtQag89baQtjFwQFRG1t/29cacc2916819498d669921833c88ceb/8-min.png?fm=png&amp;q=85&amp;w=1000" alt="PWA" width="1000" height="563" loading="lazy"></p>
<h3 id="heading-fundamentals">Fundamentals</h3>
<p>PWAs are a highly responsive and easily shareable solution, which can work offline. They store HTML and CSS files in the browser cache and archive them with service workers. This makes it possible to use the web page offline. Service workers are one of the three essential components of a PWA, along with the manifest file and a secure protocol HTTPS.</p>
<p><strong>Service workers</strong> are JavaScript code components which play the role of a proxy between the network and the browser. </p>
<p>When you open a web page for the first time, service workers store the necessary data in the browser cache. When you open it for the second time, service workers retrieve this data from the cache even before the app checked network availability. </p>
<p>Not only do they provide the ability to work offline but also they greatly boost the response time. Service workers also manage push notifications.</p>
<p><strong>The manifest file</strong> is a JSON file containing all the information about your app. For instance, it contains data about the home screen icon of your PWA, its short name, color palette, or theme. </p>
<p>If you are using the Chrome browser on an Android phone, the manifest file will trigger the automatic installation of the PWA onto your phone.</p>
<p><strong>The secure HTTPS protocol</strong> is an absolute must if you develop a progressive web app. While service workers make the very concept of a PWA possible, they are vulnerable to network errors or breaches. Service workers can intercept network requests and modify responses. To ensure data security and network security, the secure protocol needs to be used.</p>
<h3 id="heading-success-stories">Success stories</h3>
<p>Twitter is not the only company that has benefited from PWAs. Check out these <a target="_blank" href="https://developers.google.com/web/showcase/">case studies</a> published by Google to see how this technology helped popular businesses succeed. Among these companies are <a target="_blank" href="https://www.pinterest.com/">Pinterest</a>, <a target="_blank" href="https://www.alibaba.com/">Alibaba</a>, <a target="_blank" href="https://weather.com/">The Weather Channel</a>, <a target="_blank" href="https://www.lancome.com/">Lancome</a>, and <a target="_blank" href="https://www.homedepot.com/">The Home Depot.</a></p>
<h2 id="heading-2-what-is-an-amp">2. What Is an AMP?</h2>
<p>AMP stands for accelerated mobile page. It's a mobile-friendly web page, which is designed to be loaded instantly. It is a fast and smoothly loading solution which is developed with the user experience in mind. Introduced as an open-source project, the AMP technology was integrated by Google in February 2016.</p>
<p>In 2016, <a target="_blank" href="https://www.theguardian.com/membership/2016/feb/24/todays-release-of-accelerated-mobile-pages-amp">The Guardian announced</a> that their platform was now available as an AMP. To help readers see how it worked, they displayed the same article both as <a target="_blank" href="https://www.theguardian.com/us-news/commentisfree/2016/feb/16/thomas-piketty-bernie-sanders-us-election-2016">a web version</a> and <a target="_blank" href="https://amp.theguardian.com/us-news/commentisfree/2016/feb/16/thomas-piketty-bernie-sanders-us-election-2016">an AMP version</a>. </p>
<p>There were some differences, but they were insignificant. But what you'd notice right away was how much faster the AMP article loaded compared to the regular web article.</p>
<p><img src="https://images.ctfassets.net/6xhdtf1foerq/1ARjDXZC1yH4p15rxRosIW/e23cf5144729c5985e5a8ac156fb66a6/2.7_billion_people_use_smartphones__1_-min.png?fm=png&amp;q=85&amp;w=1000" alt="*By comparing this illustration with the one I included earlier, you could notice an interesting point. A PWA needs to be installed. In turn, you do not need to install AMP. It is accessed via a different like.
" width="1000" height="563" loading="lazy">
<em>*By comparing this illustration with the one I included earlier, you could notice an interesting point. A PWA needs to be installed. In turn, you do not need to install AMP. It is accessed via a different like.</em></p>
<h3 id="heading-fundamentals-1">Fundamentals</h3>
<p>The idea of AMPs is to reduce the amount of unnecessary content and functionality so that the app displays essential content immediately. The data can be reduced up to ten times. The three essential components of AMPs are AMP HTML, AMP Components, and the AMP Cache.</p>
<p><strong>AMP HTML</strong> is a simplified version of regular HTML. AMP HTML does not allow some tags and elements of HTML (for example, forms). To understand better what AMP HTML should look like, check out the <a target="_blank" href="https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/?referrer=ampproject.org">required mark-up</a>.</p>
<p><strong>AMP Components</strong> are the scripts that enable you to do without JavaScript. The idea of AMP is to get rid of all JavaScript scripts as make pages load more slowly. </p>
<p>But this does not mean that your page should do without animations, modified layouts, analytics data, autocomplete suggestions, or ads. There is an extensive <a target="_blank" href="https://amp.dev/documentation/components/?referrer=ampproject.org">library of components</a> that enable you to implement these and a lot of other features.</p>
<p><strong>The AMP Cache</strong> is a proxy-based content delivery network which fetches and caches page content. AMP Cache enables you as an app owner to easily introduce page updates. It optimizes and, if needed, modifies the AMP.</p>
<h3 id="heading-success-stories-1">Success stories</h3>
<p>The same as with PWAs, companies are often very proud of the business advantages that AMPs offer. Here is a collection of <a target="_blank" href="https://amp.dev/success-stories/">success stories</a> and case studies of companies that used AMPs and benefited from them. <a target="_blank" href="https://www.musement.com/us/">Musement</a>, <a target="_blank" href="http://www.rcsmediagroup.it/">RCS MediaGroup</a>, <a target="_blank" href="https://www.cnbc.com/">CNBC</a>, <a target="_blank" href="https://www.washingtonpost.com/">The Washington Post</a> are all companies that have implemented or plan to implement AMPs.</p>
<h2 id="heading-3-how-are-pwas-and-amps-similar">3. How Are PWAs and AMPs similar?</h2>
<p>Both PWAs and AMPs are methods of displaying web pages on mobile devices. Both of them are created to enhance the user experience. </p>
<p>AMPs and PWAs both help reduce page load time. While AMPs may be slightly more effective in terms of loading speed than PWAs, the difference between AMP and PWA loading times is barely noticeable. </p>
<p>Both technologies are actively supported by Google. There is <a target="_blank" href="https://developers.google.com/web/progressive-web-apps">a PWA page on Google Developers</a> and <a target="_blank" href="https://developers.google.com/amp">an AMP page on Google Developers</a> as well.</p>
<p>There are not a lot of other similarities, but this primary similarity is essential. </p>
<p>Now let’s see what the differences are. </p>
<h2 id="heading-4-how-are-pwas-and-amps-different">4. How Are PWAs and AMPs Different?</h2>
<h3 id="heading-appearance">Appearance</h3>
<p>By using a PWA you do not feel like you are using a web page. PWAs look and feel like a mobile app.</p>
<p>By using AMPs, you are well aware that you are using a web page because it looks the same.</p>
<h3 id="heading-development">Development</h3>
<p>In the case of PWAs, the application code is written either from scratch or with some parts of the existing code.</p>
<p>In the case of AMPs, the existing code of a web page is stripped of unnecessary CSS and JS so that the web page loads faster.</p>
<h3 id="heading-user-experience">User experience</h3>
<p>PWAs offer a much better user experience. They have push-notifications, a home screen icon, and no browser tabs. Also, they are much easier to download and lighter in size than a regular mobile app. PWAs load faster than a regular web version because they are embedded with App Shell. And PWAs can be used when the network connection is down.</p>
<p>AMPs offer a slightly improved user experience since the page loads faster than a regular page. Still, this is the only UX advantage that they offer. Unlike PWAs, AMPs cannot work offline.</p>
<h3 id="heading-performance">Performance</h3>
<p>From an SEO standpoint, AMP wins the competition. Google favors these pages and lists them in the carousel of top stories, which can increase your click-through rate.</p>
<p>PWAs, in turn, do not have a direct advantage for SEO. However, better user experience translates into higher retention rates, which helps you win with SEO.</p>
<h3 id="heading-support">Support</h3>
<p>PWAs are not supported equally on all devices, so you may find slight inconveniences when they're displayed on iOS. Also, they do not support all the hardware functionalities, such as Bluetooth, NFC, GPS, or accelerometers.</p>
<p>AMPs are supported by all major browsers on all devices.</p>
<h3 id="heading-apps-theyre-best-suited-for">Apps they're best suited for</h3>
<p>PWAs work perfectly for apps that require user interactions. E-commerce websites, social media, or online learning platforms where the app needs to be responsive and constantly updated can make use of this technology. This is why Twitter uses a PWA, for example.</p>
<p>AMPs are more suitable for platforms with a wall of content, such as online magazines or newspapers. AMPs load content instantly, but the interaction opportunities are limited. This is why The Guardian decided to employ AMPs.</p>
<h2 id="heading-5-why-pwas-are-better-than-web-pages">5. Why PWAs Are Better Than Web Pages</h2>
<p>If you access a web page on mobile, you will have to deal with browser tabs, slow loading times, and annoying pop-ups. If your device has a relatively small screen or a slow network connection, surfing the web on it becomes unbearable.</p>
<p>This problem is solved by progressive web apps. In a few clicks, you install the app on your phone and get down to using it. No need to type a link, no browser tabs, and no pop-up screens. The app works fast, and it does work if the network connection is down.</p>
<p>Alright, the benefits of this solution are evident, but it seems like native mobile apps could work perfectly instead. No, they would not. Let’s see why PWAs are better than native mobile apps.</p>
<h2 id="heading-6-why-pwas-are-better-than-native-mobile-apps">6. Why PWAs Are Better Than Native Mobile Apps</h2>
<p>To use a native mobile application, you have to find it in the App Store or Google Play catalogs. Then, you have to wait for some time to download it. You might not have enough free space on your device, so you'll need to find some room.</p>
<p>In turn, PWAs are installed and ready to use in seconds. The file size is small (although it's bound to increase while you are using the app and it is caching). Still, the size of the cached data depends on the amount of free storage you have on your device.</p>
<p>As you can see, PWAs seem better than a web or native mobile app. But you should understand that this solution is not universal. Check out my recent article on <a target="_blank" href="https://keenethics.com/blog/progressive-web-apps-vs-native-which-to-choose-and-when">PWA vs Native</a> to learn when a native app is a better choice than a PWA.</p>
<h2 id="heading-7-why-amps-are-better-than-web-pages">7. Why AMPs Are Better Than Web Pages</h2>
<p>As mentioned above, web apps are slow and inconvenient, especially when accessed on mobile devices with small screen size or underpowered hardware.</p>
<p>By getting rid of all the web components that are unnecessary for a good user experience, accelerated mobile pages solve this problem. AMPs perform 4 times faster and use 10 times less data than regular web pages.</p>
<h2 id="heading-8-why-amps-are-not-better-than-native-mobile">8. Why AMPs Are NOT Better Than Native Mobile</h2>
<p>Unfortunately, AMPs cannot be a complete substitute for native mobile apps. They cannot be installed on the home screen, they still include browser tabs, and their functionality is limited to some basic stuff.</p>
<p>But for an online newspaper or for an informational website, such as <a target="_blank" href="https://www.webmd.com/">WebMD</a>, it is better to use AMPs rather than a native mobile app. These do not require any additional functionality for displaying page content.</p>
<h2 id="heading-to-wrap-up">To Wrap Up</h2>
<p>Both AMPs and PWAs are powerful technologies. To sum up the results of our initial question - PWAs vs AMPs: </p>
<ul>
<li>AMPs will be easier, faster, and cheaper for you to develop </li>
<li>PWA will offer more benefits.</li>
</ul>
<p>Just remember - neither of them is a universal solution, and neither is a panacea. Even using AMPs and PWAs together may not meet all your demands. Sometimes you may need to choose more conventional types of software. </p>
<p>If you are still not sure what to choose, our specialists share <a target="_blank" href="https://www.freecodecamp.org/news/four-questions-to-understand-if-you-need-pwa/">four questions to understand if you need PWA</a>. In short: <em>We believe that progressive web apps are the future. Accelerated mobile pages are just too simple and limited in functionality to compete.</em></p>
<h2 id="heading-do-you-have-an-idea-for-a-project">Do you have an idea for a project?</h2>
<p>My company KeenEthics is experienced in both AMP and <a target="_blank" href="https://keenethics.com/tech-apps-progressive-web-apps">progressive web app development</a>. If you are ready to change the game and start your project, feel free to <a target="_blank" href="https://keenethics.com/contacts">get in touch</a><em>.</em></p>
<h2 id="heading-ps">P.S.</h2>
<p>The original article posted on KeenEthics blog can be found here: <a target="_blank" href="https://keenethics.com/blog/pwa-vs-amp">PWA vs AMP:  What Is the Difference and How Do You Choose?</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to programmatically build a Spotify clone for iOS using AutoLayout: adding photos and updating the UI ]]>
                </title>
                <description>
                    <![CDATA[ By Said Hayani This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and check it now.  In this article, we are going to add some mocked pictur... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-spotify-clone-for-ios-with-autolayout-programmatically-part-2/</link>
                <guid isPermaLink="false">66d460d2868774922c885008</guid>
                
                    <category>
                        <![CDATA[ 100DaysOfCode ]]>
                    </category>
                
                    <category>
                        <![CDATA[ app development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ autolayout ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iOS13 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ iphone ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ User Interface ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 10 Dec 2019 03:44:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/12/featured_image-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Said Hayani</p>
<p>This is the second part of an article on building a Spotify UI clone with autoLayout programmatically. If you missed the first part, no worries - just please go and <a target="_blank" href="https://www.freecodecamp.org/news/autolayout-programmatically-spotify-clone-in-swift/">check it now</a>. </p>
<p>In this article, we are going to add some mocked pictures and try to make the UI look the same as Spotify's.</p>
<p>This is what we are going to do today ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is were we left off in the first part:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/complet-layout-demo1.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The next step is to create customized cells. So let's start by creating one with the name  <code>SubCustomCell</code>.</p>
<p>First, create a new Swift file inside the project folder and name it <code>SubCustomCell.swift</code>. This file will contain our custom cell that will represent the Playlist. After creating the file, try to add in the code below and initialize the cell, maybe with <code>backgroundColor</code>,  to see the UI changes when we register the cell with the <code>collectionView</code>. </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> UIKit

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SubCustomCell</span>: <span class="hljs-title">UICollectionViewCell</span> </span>{
        <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        backgroundColor = .red
    }

    <span class="hljs-keyword">required</span> <span class="hljs-keyword">init</span>?(coder aDecoder: <span class="hljs-type">NSCoder</span>) {
        <span class="hljs-built_in">fatalError</span>(<span class="hljs-string">"init(coder:) has not been implemented"</span>)
    }
}
</code></pre>
<p>Then we register the <code>SubCustomCell</code>  inside <code>CustomCell.swift</code> within the <code>init</code> block. Replace <code>UICollectionViewCell.self</code> with  <code>SubCustomCell</code> like below.</p>
<pre><code class="lang-swift"> collectionView.register(<span class="hljs-type">SubCustomCell</span>.<span class="hljs-keyword">self</span>, forCellWithReuseIdentifier: cellId)
</code></pre>
<p>Also we need to make a modification on the <code>cellForItemAt</code> method and make it conform to  <code>SubCustomCell</code> like the following.</p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// cell.backgroundColor = .yellow</span>

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>You should see the <code>backgroundColor</code> changed to <code>red</code> .</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.10.25-AM.png" alt="Image" width="600" height="400" loading="lazy">
<em>Swift CustomCell</em></p>
<p>Up until this point everything should be straightforward and clear.</p>
<p>Now we're going to fill the cells with some mocked pictures and create an <code>ImageView</code> inside each cell. I already downloaded some random pictures from <a target="_blank" href="https://www.pexels.com/">pexels.com,</a> but feel free to use any pictures you like (including these). You can find them in the <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift">project files on Github</a>.</p>
<p>Let's create the <code>UIImageView</code> inside <code>SubCustomCell.swift</code> and make some constraints.</p>
<pre><code class="lang-swift">    <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And add it to the <code>view</code> within the <code>init</code> block using <code>addSubView</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">override</span> <span class="hljs-keyword">init</span>(frame: <span class="hljs-type">CGRect</span>) {
        <span class="hljs-keyword">super</span>.<span class="hljs-keyword">init</span>(frame: frame)
        addSubview(<span class="hljs-type">ImageView</span>)

    }
</code></pre>
<p>Now let's make the <code>ImageView</code> take up all the space within the cell with the constraints below.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = <span class="hljs-literal">true</span>
</code></pre>
<ul>
<li><code>LeftAnchor</code> represents the left anchor of the cell</li>
<li><code>rightAnchor</code> represents the right anchor of the cell</li>
<li><code>bottomAnchor</code> represents the bottom anchor of the cell </li>
<li><code>topAnchor</code> represents the top anchor of the cell</li>
</ul>
<p>And by making <code>ImageView</code> 's top anchor equal to the cell's top anchor (and doing the same for <code>ImageView</code> 's left, right, and bottom anchor) it makes the <code>ImageView</code> take up all the space of the <code>SubCustomCell</code> (cell).</p>
<p>Note: first you need to use <code>translatesAutoresizingMaskIntoConstraints</code> to be able to apply the constraints to the elements. Also don't forget to call <code>isActive</code> property and assign it to <code>true</code> – without doing that the constraints won't work and nothing will change.</p>
<p>The <code>ImageView</code> should have an image, so let's add one.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">ImageView</span> : <span class="hljs-type">UIImageView</span> = {
       <span class="hljs-keyword">let</span> iv = <span class="hljs-type">UIImageView</span>()
        iv.backgroundColor = .yellow
        <span class="hljs-comment">// we have &gt;image1&lt; file inside the project </span>
        iv.image = <span class="hljs-type">UIImage</span>(named: <span class="hljs-string">"image1"</span>)
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = <span class="hljs-literal">true</span>

        <span class="hljs-keyword">return</span> iv

    }()
</code></pre>
<p>And if you build and run the app, you should see the results and picture we added to the <code>SubCustomCell</code>.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-03-at-1.37.51-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Cool ?. Now there is an element we should add to the <code>SubCustomCell</code> to finish up. We need a title that will represent the title of the playlist:  <code>UILabel</code>.</p>
<p>For the title it will be like this:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">let</span> <span class="hljs-type">TitleLabel</span> : <span class="hljs-type">UILabel</span> = {
        <span class="hljs-keyword">let</span> lb = <span class="hljs-type">UILabel</span>()
        lb.textColor = <span class="hljs-type">UIColor</span>.lightGray
        lb.font = <span class="hljs-type">UIFont</span>.systemFont(ofSize: <span class="hljs-number">16</span>)
        lb.font = <span class="hljs-type">UIFont</span>.boldSystemFont(ofSize: <span class="hljs-number">20</span>)
        lb.text = <span class="hljs-string">"Evening Music"</span>

        <span class="hljs-keyword">return</span> lb
    }()
</code></pre>
<p>I just put some random text there – you can put whatever you like. The next step is to add the element to the view and give it some constraints. The title will be placed at the bottom of the <code>ImageView</code>.</p>
<h3 id="heading-add-to-view">Add to view:</h3>
<pre><code class="lang-swift">addSubview(<span class="hljs-type">TitleLabel</span>)
</code></pre>
<h3 id="heading-applying-the-constraints-for-both-the-imageview-and-the-titlelabel">Applying the constraints for both the <code>ImageView</code> and the <code>TitleLabel</code></h3>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">ImageView</span>.topAnchor.constraint(equalTo: topAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.leftAnchor.constraint(equalTo: leftAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.rightAnchor.constraint(equalTo: rightAnchor).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">240</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor).isActive = <span class="hljs-literal">true</span>



            <span class="hljs-type">TitleLabel</span>.translatesAutoresizingMaskIntoConstraints = <span class="hljs-literal">false</span>
            <span class="hljs-type">TitleLabel</span>.topAnchor.constraint(equalTo: <span class="hljs-type">ImageView</span>.bottomAnchor,constant: <span class="hljs-number">10</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.leftAnchor.constraint(equalTo: leftAnchor, constant: <span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
            <span class="hljs-type">TitleLabel</span>.rightAnchor.constraint(equalTo: rightAnchor, constant: -<span class="hljs-number">5</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go!</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-1.45.10-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>We made the picture take up most of the space in the cell, and the rest is taken up by the title. As you can see, you can scroll horizontally in each section and also vertically in the entire screen.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo2.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now we are put some mock data into the cells to make it feel like it's real. For that I created a <code>JSON</code> file that contains some random data for sections and playlists.</p>
<p>First let's create a two structs, <code>Section</code> and <code>Playlist</code> . We create a separate file for each struct. </p>
<p> <code>section.swift</code> </p>
<pre><code class="lang-swift"><span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Section</span> </span>{
    <span class="hljs-keyword">var</span> title : <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> playlists : <span class="hljs-type">NSArray</span>
    <span class="hljs-keyword">init</span>(dictionary:[<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.playlists = dictionary[<span class="hljs-string">"playlists"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">NSArray</span> ?? []

}
}
</code></pre>
<p><code>playlist.swift</code></p>
<pre><code class="lang-swift"><span class="hljs-comment">//</span>
<span class="hljs-comment">//  playlist.swift</span>
<span class="hljs-comment">//  spotifyAutoLayout</span>
<span class="hljs-comment">//</span>
<span class="hljs-comment">//  Created by admin on 12/6/19.</span>
<span class="hljs-comment">//  Copyright © 2019 Said Hayani. All rights reserved.</span>
<span class="hljs-comment">//</span>

<span class="hljs-keyword">import</span> Foundation
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">PlayList</span> </span>{
    <span class="hljs-keyword">var</span> title: <span class="hljs-type">String</span>
    <span class="hljs-keyword">var</span> image : <span class="hljs-type">String</span>
    <span class="hljs-keyword">init</span>(dictionary : [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>]) {
        <span class="hljs-keyword">self</span>.title = dictionary[<span class="hljs-string">"title"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
        <span class="hljs-keyword">self</span>.image = dictionary[<span class="hljs-string">"image"</span>] <span class="hljs-keyword">as</span>? <span class="hljs-type">String</span> ?? <span class="hljs-string">""</span>
    }

}
</code></pre>
<p>And then inside <code>ViewController.swift</code> we create a function that fetches the JSON for us and stores the results in an array.</p>
<pre><code class="lang-swift">
        <span class="hljs-built_in">print</span>(<span class="hljs-string">"attempt to fetch Json"</span>)
        <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> path = <span class="hljs-type">Bundle</span>.main.path(forResource: <span class="hljs-string">"test"</span>, ofType: <span class="hljs-string">"json"</span>) {
            <span class="hljs-keyword">do</span> {
                  <span class="hljs-keyword">let</span> data = <span class="hljs-keyword">try</span> <span class="hljs-type">Data</span>(contentsOf: <span class="hljs-type">URL</span>(fileURLWithPath: path), options: .mappedIfSafe)
                  <span class="hljs-keyword">let</span> jsonResult = <span class="hljs-keyword">try</span> <span class="hljs-type">JSONSerialization</span>.jsonObject(with: data, options: .mutableLeaves)
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> jsonResult = jsonResult <span class="hljs-keyword">as</span>? [ <span class="hljs-type">Any</span>] {
                            <span class="hljs-comment">// do stuff</span>
                    jsonResult.forEach { (item) <span class="hljs-keyword">in</span>

                        <span class="hljs-keyword">let</span> section = <span class="hljs-type">Section</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                       <span class="hljs-comment">// print("FEtching",section.playlists)</span>
                        <span class="hljs-keyword">self</span>.sections.append(section)
                    }


                  <span class="hljs-keyword">self</span>.collectionView.reloadData()
                  }
              } <span class="hljs-keyword">catch</span> {
                   <span class="hljs-comment">// handle error</span>
              }
        }
    }
</code></pre>
<p>The <code>fetchJson</code> function is called within the <code>ViewDidLoad</code> method. We also have a variable called <code>sections</code> where we store the results:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> sections = [<span class="hljs-type">Section</span>]()
</code></pre>
<p>The next step is to pass the data from <code>ViewController</code> to <code>CustomCell</code>. For that we create a variable inside <code>CustomCell</code> which will receive the data for each section: </p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span>{
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>We use <code>cellForItemAt</code>  inside the <code>ViewController</code> method to pass the data directly to the <code>CustomCell</code> .</p>
<pre><code class="lang-swift"><span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">CustomCell</span>

        cell.section = sections[indexPath.item]

        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>Note: we always call <strong><code>self</code></strong><code>.collectionView.reloadData()</code> every-time <code>fetchJson</code> is called so the block below, inside <code>CustomCell</code>, will be called as well. Check the console, <code>shift</code> + command + C:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
        }
    }
</code></pre>
<p>The first thing we change is to set the the section title:</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
        }
    }
</code></pre>
<p>And then you should see that each section has a specific title on the screen ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-06-at-3.23.32-AM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Now it's time to pass the data down to <code>SubCustomCell</code>. We do the same thing as we did above. We need to pass the <code>playlists</code> array, so we create a variable named <code>playlists</code> inside <code>CustomCell</code>.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> playlists : [<span class="hljs-type">PlayList</span>]() <span class="hljs-comment">//empty</span>
</code></pre>
<p>First, we map through the <code>playlists</code>  from the <code>JSON</code>. Then we add each playlist with the <code>playlists</code> var.</p>
<pre><code class="lang-swift"> <span class="hljs-keyword">var</span> section : <span class="hljs-type">Section?</span> {
        <span class="hljs-keyword">didSet</span>{
            <span class="hljs-built_in">print</span>(<span class="hljs-string">"section ✅"</span>,<span class="hljs-keyword">self</span>.section)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> section = <span class="hljs-keyword">self</span>.section <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-keyword">self</span>.titleLabel.text = section.title
            <span class="hljs-comment">// append to playlists array</span>
             <span class="hljs-keyword">self</span>.section?.playlists.forEach({ (item) <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">let</span> playlist = <span class="hljs-type">PlayList</span>(dictionary: item <span class="hljs-keyword">as</span>! [<span class="hljs-type">String</span> : <span class="hljs-type">Any</span>])
                <span class="hljs-keyword">self</span>.playlists.append(playlist)

            })
            <span class="hljs-keyword">self</span>.collectionView.reloadData()
        }
    }
</code></pre>
<p>Attention! If you try to run the app it may crash. This is because we forgot to set the number of sections. Since we are now receiving the data from JSON, the number should be dynamic based on the number of sections we have. The number of sections should be equal to the number of sections inside the <code>JSON</code>, so we need to modify <code>numberOfItemsInSection</code> inside <code>ViewController</code> to the below :</p>
<pre><code class="lang-swift">   <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span> sections.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>We do the same thing with the same method inside <code>CustomCell.swift</code> – but here we consider the number of the <code>playlists</code> instead.</p>
<pre><code class="lang-swift"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, numberOfItemsInSection section: Int)</span></span> -&gt; <span class="hljs-type">Int</span> {
        <span class="hljs-keyword">return</span>  <span class="hljs-keyword">self</span>.playlists.<span class="hljs-built_in">count</span>
    }
</code></pre>
<p>The last step we have to complete is to pass each single playlist <code>Object</code> to <code>SubCustomCell</code> within <code>cellForItemAt</code> in <code>CustomCell.swift</code>. </p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">UICollectionViewCell</span> {
        <span class="hljs-keyword">let</span> cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">SubCustomCell</span>
        <span class="hljs-comment">// here ?</span>
        cell.playlist = playlists[indexPath.item]
        <span class="hljs-keyword">return</span> cell
    }
</code></pre>
<p>And we are going to get that data inside <code>SubCustomCell</code> via the <code>playlist</code> variable and finally display the title and image of the playlist.</p>
<pre><code class="lang-swift"><span class="hljs-keyword">var</span> playlist : <span class="hljs-type">PlayList?</span> {
           <span class="hljs-keyword">didSet</span>{
               <span class="hljs-built_in">print</span>(<span class="hljs-string">"Playlist ?"</span>,<span class="hljs-keyword">self</span>.playlist)
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> playlist = <span class="hljs-keyword">self</span>.playlist <span class="hljs-keyword">else</span> {<span class="hljs-keyword">return</span>}
            <span class="hljs-comment">// The Image ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">ImageView</span>.image = <span class="hljs-type">UIImage</span>(named: playlist.image)
            <span class="hljs-comment">// the playlist title ?</span>
            <span class="hljs-keyword">self</span>.<span class="hljs-type">TitleLabel</span>.text = <span class="hljs-keyword">self</span>.playlist?.title

           }
       }
</code></pre>
<p>I think everything should work fine now, just as below ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo3.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p> One last update to the UI: we have to add some padding and margins to the <code>section</code>  and <code>playlist</code> titles and make the playlist a little bit smaller.</p>
<p>Let's first add some padding for the section titles. To do that, we need just to give the <code>constant</code> property some number value inside the section cell <code>CustomCell</code> and within <code>setupSubCells</code>: </p>
<pre><code class="lang-swift"> collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor,constant: <span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And if you see the entire <code>collectionView</code> come in at the bottom of the <code>titleLabel</code>, all we need to do is add more space by adding <code>15</code>:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/paddingForTitles-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Next we come to the title of the <code>playlist</code>. This will be inside <code>SubCustomCell</code>, and we just need to add more space at the bottom of the ImageView.</p>
<pre><code class="lang-swift"> <span class="hljs-type">ImageView</span>.bottomAnchor.constraint(equalTo: <span class="hljs-type">TitleLabel</span>.topAnchor,constant: -<span class="hljs-number">15</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>We already have the constant there. In order for it to work, the value should be <code>-15</code></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/demo4.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Finally the playlist needs to be a little bit smaller. This is easy: we just make the <code>playlist</code> cell's height and width equal to the <code>section</code> cell's height divided by 2, just like below:</p>
<p><code>CustomCell.swift</code></p>
<pre><code class="lang-swift"> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">collectionView</span><span class="hljs-params">(<span class="hljs-number">_</span> collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)</span></span> -&gt; <span class="hljs-type">CGSize</span> {

        <span class="hljs-keyword">let</span> width = frame.height / <span class="hljs-number">2</span>
        <span class="hljs-keyword">let</span> height = frame.height / <span class="hljs-number">2</span>

        <span class="hljs-keyword">return</span> <span class="hljs-type">CGSize</span>(width: width, height: height)

    }
</code></pre>
<p>Make the ImageView's height equal to <code>150</code> as well.</p>
<pre><code class="lang-swift">  <span class="hljs-comment">//SubCutomCell.swift</span>
  <span class="hljs-type">ImageView</span>.heightAnchor.constraint(equalToConstant: <span class="hljs-number">150</span>).isActive = <span class="hljs-literal">true</span>
</code></pre>
<p>And here we go ?.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/12/Screen-Shot-2019-12-09-at-9.55.19-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Perfect! I think that's enough for today – I don't want to make this article too long. So we will have another part where we will add the <code>TabBar</code> and the description, as well as some icons for the playlist.</p>
<p><strong>View the</strong> <a target="_blank" href="https://github.com/hayanisaid/autoLayout-programmatically-in-swift"><strong>Full source code on GitHub</strong></a><strong>?.</strong></p>
<p>Thanks for your time. I hope I haven't missed anything. If I did please @mention me on <a target="_blank" href="https://twitter.com/SaidHYN">Twitter</a>, or if you have any questions or an addition to this post the doors are always open to anyone. Thanks??.</p>
<p><strong><a target="_blank" href="https://webege.us16.list-manage.com/subscribe?u=311846a57d1e1a666287ad128&amp;id=2b386b2ebb">Subscribe</a></strong> <em>to my email list to be notified when the third part of this tutorial is published.</em> </p>
<blockquote>
<p>By the way, I’ve recently worked with a strong group of software engineers for one of my mobile applications. The organization was great, and the product was delivered very quickly, much faster than other firms and freelancers I’ve worked with, and I think I can honestly recommend them for other projects out there. Shoot me an email if you want to get in touch — <a target="_blank" href="mailto:said@devsdata.com">said@devsdata.com</a>.</p>
</blockquote>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use freeCodeCamp on a mobile phone ]]>
                </title>
                <description>
                    <![CDATA[ By Jackson Bates For 5 years, freeCodeCamp has been helping millions to learn to code for...well...free! The low cost has opened up a world of opportunity to those that could not afford a bootcamp or the many expensive courses available. However, the... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/freecodecamp-mobile/</link>
                <guid isPermaLink="false">66d45f3547a8245f78752a50</guid>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 18 Oct 2019 20:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2019/10/commlinechic-3.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Jackson Bates</p>
<p>For 5 years, freeCodeCamp has been helping millions to learn to code for...well...free!</p>
<p>The low cost has opened up a world of opportunity to those that could not afford a bootcamp or the many expensive courses available. However, there has been one barrier to entry for some - the necessity to use a laptop / desktop PC.</p>
<p>Coding on freeCodeCamp has been <em>possible</em> on a mobile device, but it's never been a comfortable experience - until today!</p>
<p>With the 5th birthday of freeCodeCamp comes a wonderful gift to the developer community: the new <em>Command Line Chic</em> interface, which includes a far superior mobile experience than has previously been available.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/commlinechic.gif" alt="Image" width="600" height="400" loading="lazy">
<em>The new responsive command line chic interface, with a clean mobile text editor</em></p>
<h2 id="heading-making-the-most-of-mobile-coding">Making the most of mobile coding</h2>
<p>Maybe you've tried using your mobile device for coding on freeCodeCamp before and noticed an annoying bug - it's impossible to delete things properly!</p>
<p>If you have encountered this, the cause of the problem is simple - your keyboard suggestions are treating the individual characters as longer strings. I haven't investigated this in detail, but my intuition is that it's deleting the html entity code.</p>
<p>The fix is simple - turn off auto suggestions, or better yet <strong>use a dedicated coding keyboard for your device</strong>. </p>
<p>This has the added benefit of making they keys you use often for programming (but not natural language) more easily available, such as brackets, braces and other special characters.</p>
<h2 id="heading-coding-keyboards-for-your-mobile-device">Coding keyboards for your mobile device</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/codeboard.png" alt="Image" width="600" height="400" loading="lazy">
<em>CodeBoard for Andoid</em></p>
<p><a target="_blank" href="https://play.google.com/store/apps/details?id=com.gazlaws.codeboard">CodeBoard for Android</a> provides a packed keyboard of all the keys you are likely to need while completing the freeCodeCamp curriculum. The board is a little too crowded on a phone (although I still use it and have gotten used to it), but on a tablet it is a perfect companion.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/10/ioscodeboard.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>DevKey for iOs</em></p>
<p><a target="_blank" href="https://apps.apple.com/us/app/devkey-developer-keyboard-for-programming/id961304986">DevKey for iOs</a> presents a much less crowded interface, while still providing most of the keys you are likely to need. I can't personally endorse this, since I do not have an iPhone - but needless to say it presents a better experience for mobile coding than the standard keyboards.</p>
<h2 id="heading-coding-on-the-go">Coding on the go!</h2>
<p>Now that you've supercharged your mobile learning environment, you can take those freeCodeCamp lessons with you wherever you go, without the need for a clunky laptop hotspotting off your phone.</p>
<p>One thing that I'm really looking forward to is using the new interface and my mobile set-up to increase my participation on the <a target="_blank" href="https://freecodecamp.org/forum">freeCodeCamp forum</a>! I've always primarily engaged with the forum on my phone, but have struggled to help with coding challenges due to the previously poor mobile experience. Now, you can expect to get even more help from me and hopefully others!</p>
<p>Happy birthday, freeCodeCamp, and happy coding, y'all!</p>
<p> You can follow my more informal tech ramblings on Twitter <a target="_blank" href="https://twitter.com/jacksonbates">@JacksonBates</a>!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The story of one mother & two sons: value type vs reference type in Swift ]]>
                </title>
                <description>
                    <![CDATA[ By Boudhayan Biswas Swift is a mother?and it has two sons ?- Value Type ??‍♀️ Reference Type ?‍♂️ But what are their characteristics??‍♂️ Do they behave the same or opposite to each other? ?‍♂️ Swift is a multi-paradigm programming language develop... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-story-of-one-mother-two-sons-value-type-vs-reference-type-in-swift-6e125af2d5d0/</link>
                <guid isPermaLink="false">66d45de255db48792eed3f49</guid>
                
                    <category>
                        <![CDATA[ iOS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Swift ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Tue, 21 May 2019 16:47:32 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*Ri49w8TcHeXrnmO5dD4_aQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Boudhayan Biswas</p>
<p>Swift is a mother?and it has two sons ?-</p>
<ul>
<li>Value Type ??‍♀️</li>
<li>Reference Type ?‍♂️</li>
</ul>
<p>But what are their characteristics??‍♂️</p>
<p>Do they behave the same or opposite to each other? ?‍♂️</p>
<p>Swift is a multi-paradigm programming language developed by Apple for iOS, macOS, watchOS, tvOS, Linux, and z/OS.?</p>
<p>Just like other object-oriented programming languages, Swift has classes as building blocks which can define methods, properties, initializers, and can conform to protocols, support inheritance &amp; polymorphism.?</p>
<p>But, wait wait wait…???</p>
<p>Swift has structs also and it can define methods, properties, initializers and can conform to protocols with only one exception of inheritance.?</p>
<p>What? Now I am confused!!! ???</p>
<p>Now let’s spice up your confusion: structs are not only the value types in Swift. Tuples and enums are also value types. Classes are also not the only one used as a reference type. Functions and closures are also reference types. But as a token of relief, we at least know the primary focus &amp; specialization of usage of these types.?</p>
<p>So up to this point, we are left with only one big confusion with the usage of structs and classes.?</p>
<p>So, let’s go and clear the confusions going around.?‍♂️</p>
<h3 id="heading-storage-locations">Storage Locations</h3>
<p>There are three types of storage available:</p>
<ul>
<li>Register ?</li>
<li>Stack ☄️</li>
<li>Heap ?</li>
</ul>
<p>The objects that have a shorter lifespan are stored inside registers or the stack and those that have a longer lifespan are stored inside the heap.?</p>
<p>A value type stores its contents in memory allocated in the stack, so we can say value types are allocated in the stack in Swift. ?</p>
<p>But there is a common misconception about value types, have you heard it??‍♂️</p>
<p>The misconception is that most people think value types are always stored in the Stack.</p>
<p>❌❌ Wait a minute — this is not the case always. ❌❌</p>
<p>Value types can be stored inside the stack when they are either temporary or local variables. But what if a value type is contained inside a reference type?</p>
<p>In this situation, it can be stored inside the heap memory. ?</p>
<p>Wow…that’s cool!!!?</p>
<p>So the value types can be stored inside the register, stack or heap depending on their lifespan, whether they are short lived or long lived. If it is a local variable it can live inside the stack and if it is a part of class then it can live inside heap memory also.✅</p>
<p>On the other hand, reference type stores its contents in memory allocated in the heap memory and the variable holds only a reference to that memory location where actual data has been stored. ??</p>
<p>How does it work for reference type??</p>
<p>So for reference type, it is quite a common situation when there can be several variables holding the reference to the same memory location.⚔️</p>
<p>When a value type instance is assigned to a variable or passed to a function, the instance is copied and assigned to that variable. But with the reference type, only the reference gets copied and the new variable holds the same reference to the same memory location. ?</p>
<h3 id="heading-differences-in-terms-of-mutability">Differences in terms of Mutability</h3>
<p>There can be two states for a variable:</p>
<ul>
<li>?‍♀ ️Mutable ?‍♀</li>
<li>?️‍♂️ Immutable ?️‍♂️</li>
</ul>
<p>If a value type instance is assigned to an immutable variable, then the instance also becomes immutable. As a result, we can not make any changes to that instance.?‍♂️</p>
<p>If a value type instance is assigned to a mutable variable, then only it makes the instance mutable. ?‍♂️</p>
<p>But things are totally different for reference types. The variable and the instance it is assigned to are totally different. If we declare an immutable variable holding a reference to a class, this means that the reference it is holding will never change. We can not the change the reference and it will always point to the same reference. ?</p>
<h3 id="heading-structural-types">Structural Types</h3>
<p>Values of structural types are compared for equality in terms of their attributes or elements. We can say a value type is equal to another if and only if all of the corresponding attributes are equal. ???</p>
<p>Umm…too many strong words…what do you mean???</p>
<p>Let’s say, we have a <strong><em>Person</em></strong> value type which has attributes like <strong><em>firstName</em></strong> and <strong><em>lastName.</em></strong></p>
<pre><code>struct Person {
   <span class="hljs-keyword">var</span> firstName: <span class="hljs-built_in">String</span>
   <span class="hljs-keyword">var</span> lastName: <span class="hljs-built_in">String</span>
}

<span class="hljs-keyword">var</span> person1 = Person(firstName: <span class="hljs-string">"foo"</span>, <span class="hljs-attr">lastName</span>: <span class="hljs-string">"bar"</span>)

<span class="hljs-keyword">var</span> person2 = Person(firstName: <span class="hljs-string">"foo"</span>, <span class="hljs-attr">lastName</span>: <span class="hljs-string">"bar"</span>)
</code></pre><p>Here both <strong><em>person1</em></strong> &amp; <strong><em>person2</em></strong> instances are holding the same value for <strong><em>firstName</em> (“foo”)</strong> and <strong><em>lastName (“bar”)</em></strong><em>.</em> So as per our understanding, we can say that the two instances are equal to each other since their attributes (<strong><em>firstName</em></strong> &amp; <strong><em>lastName</em></strong>) are holding the same values.</p>
<p>But it’s not only limited to this: in the future, any two person instances holding the same values for <strong><em>firstName</em></strong> &amp; <strong><em>lastName</em></strong> will be equal to each other.</p>
<p>So as per our understanding till this point, we can say that:</p>
<blockquote>
<p><em><strong>Value Types do not have identity, so there can be no reference to them. Value types are faceless.?</strong></em></p>
</blockquote>
<p>What? How can you say that????</p>
<pre><code><span class="hljs-keyword">var</span> myAge: Int = <span class="hljs-number">21</span>
<span class="hljs-keyword">var</span> friendAge: Int = <span class="hljs-number">21</span>
</code></pre><p>Both <strong><em>myAge</em></strong> &amp; <strong><em>friendAge</em></strong> are integer type variable with value 21.</p>
<p><strong><em>Can we distinguish one from the other? ?</em></strong></p>
<p>No, because they are holding the same value.?</p>
<p>An integer variable with value 21 cannot be different from another integer variable which is also having the value 21. As simple as that.???</p>
<p>Not having an identity gives value types another advantage: if you think practically, then you can imagine if you do not have an identity then anyone with same characteristics can replace or substitute you. ???</p>
<p>The same we can think for us as humans also. If I don’t have an identity then anyone with same characteristics can replace me???. It’s good for us that we have an identity otherwise it would be a great risk to our existence.?</p>
<p>But for value types, they don’t have an identity and it is an advantage to them. ?</p>
<h3 id="heading-what-are-the-benefits-of-using-value-types">What are the benefits of using Value Types?</h3>
<h4 id="heading-no-race-conditions-and-deadlocks">? No Race Conditions and Deadlocks: ?</h4>
<p>For values types in a multi-threaded environment, it is impossible for one thread to mutate the state of the instance while it is being used by another thread. So we can say that there will be no race conditions or deadlocks.</p>
<h4 id="heading-no-retain-cycles">⚔️ <strong>No Retain Cycles: ⚔️</strong></h4>
<p>When there are two reference type instances that are holding strong references to each other and preventing each other from being deallocated from memory, it is called a retain cycle. Since value types don’t work as a reference, so we can say there will be no retain cycles for value types.</p>
<h4 id="heading-automatic-reference-counting">?‍?‍?‍? Automatic Reference Counting: ?‍?‍?‍?</h4>
<p>For reference type, Swift uses automatic reference counting to keep track of all the live or active objects and deallocates the instance only when there are no more strong references to it. If we think a little bit, then we can say that it is kind of a heavy operation because Swift runtime needs to keep track of the objects always. But since value types are allocated in the stack, it does not need ARC. So it is cheaper and faster??.</p>
<p>But wait...How does it manage memory for Array, Dictionary and String??</p>
<p>Since we can not know what will be the actual size of an array, a dictionary, and a string at compile time, there is no scope for them to be allocated at compile time. Though they are value types internally, they can not be allocated in stack. They need to be allocated in heap memory, and to manage this, Swift comes up with <strong><em>copy on write</em></strong>.?</p>
<p>But what is this??</p>
<p>When we say one instance is a copy of another instance, this really means they are the same, that they contain the same values. But in Swift, for these above types (Array, Dictionary, String, etc), an actual copy has been made on heap only when an instance is mutated. This is called a performance optimization technique for value types.???</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>There is no hard rule which defines when to use value type and when to use reference type. Value types have some unique advantages over reference types and vice versa. They both are unique in their own way. It really depends on your requirements and what you are trying to achieve. You should know the semantics of your code because you only know your code best, so it’s up to you to choose. You have the full freedom.</p>
<p>So rather than fighting over value type vs reference type, use them intelligently.</p>
<p><strong><em>??? Cheers!!! Thank you for reading!!</em></strong> <em>???</em></p>
<p><strong><em>✅✅✅You can find me on</em></strong> <a target="_blank" href="https://twitter.com/_boudhayan_"><strong><em>Twitter</em></strong></a><strong><em>.✅✅✅</em></strong></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to choose the best tech career path for you ]]>
                </title>
                <description>
                    <![CDATA[ By Colin Smith Dev Ops, Mobile Engineer, Data Scientist, Project Manager, and Front End — what’s best for you? _Get more info before you blindly choose your future career path. Photo by [Unsplash](https://unsplash.com/photos/ZFYg5jTvB4A?utm_source=u... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-choose-the-best-tech-career-path-for-you-61c4d5ff9a77/</link>
                <guid isPermaLink="false">66c3508d5ced6d98e4bd3343</guid>
                
                    <category>
                        <![CDATA[ careers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Data Science ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 04 Feb 2019 17:10:57 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1sibiTjlpM5AY_bkS0Zdvg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Colin Smith</p>
<h4 id="heading-dev-ops-mobile-engineer-data-scientist-project-manager-and-front-end-whats-best-for-you">Dev Ops, Mobile Engineer, Data Scientist, Project Manager, and Front End — what’s best for you?</h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/2CF0UBu9Vpz5Ga39bgLilZjt0uQhgyk3gGwi" alt="Image" width="800" height="545" loading="lazy">
_Get more info before you blindly choose your future career path. Photo by [Unsplash](https://unsplash.com/photos/ZFYg5jTvB4A?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Robert Anasch on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=").</em></p>
<p>I’ve worked in tech for four years, and I still come across roles that I don’t understand very well. There are so many ways to build a career in tech. I know that when I started looking for my first job, I was clueless about the differences between career paths. If you asked me what a site reliability engineer did, I wouldn’t have been able to tell you.</p>
<p>I get a lot of questions about career paths in tech. I thought I would write an article about it so I could point people to it. I’ll be using Business Insider’s article listing the <a target="_blank" href="https://www.businessinsider.com/best-tech-jobs-in-america-2018-2">20 best tech jobs in America in 2018 as a reference</a>. This is a good list of relevant tech paths with good upward mobility. They are highly in demand and will allow you to get a job at a good company with good pay. Hopefully, this will help you decide the path you will take. So let's start:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/BMXx4ncbet3Sf2DEBL608i8aF54kxLBvC77d" alt="Image" width="800" height="533" loading="lazy">
_Mobile devices have deeply integrated into our lives. For better or for worse. Photo by [Unsplash](https://unsplash.com/photos/5AYP1yeaE3I?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;rawpixel on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-mobile-developer">Mobile Developer</h3>
<p><strong>What do they do?</strong></p>
<p>Mobile developers are the people that build apps for companies. If you’ve ever used an Android or iOS device, then you’ve directly interacted with a mobile developer’s work. There are other development platforms for mobile such as Windows phone. But for the most part, when people say “Mobile Developer”, they’re most likely talking about an Android or iOS developer.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You should become a mobile developer if you want to <strong>use your eye for design and attention to visual detail alongside your technical prowess</strong>. Mobile developers work heavily with designers to put out beautiful, easy to use and performant mobile apps.</p>
<p>You should also choose this path if you are interested in mobile devices and how they work. Mobile developers that focus on infrastructure have to consider limited device resources. They also must have in-depth knowledge of how a mobile device works to make the apps they work on performant.</p>
<p><strong>How do I get started?</strong></p>
<p>This depends on if you want to focus on iOS or Android. I’d personally recommend learning Android for two reasons. Java is probably a more useful language to learn over Swift or Objective-C and the fact that 75% of the world uses Android compared to 21% using iOS. <a target="_blank" href="http://gs.statcounter.com/os-market-share/mobile/worldwide">This is according to statcounter.com</a>. That being said, if you have a particular passion for one platform over the other, go with your passion.</p>
<p>For Android, <a target="_blank" href="https://android.jlelse.eu/learning-android-development-in-2018-part-1-83a514f6a205">read this article</a>. This goes over the nitty-gritty of how to get started. For iOS, <a target="_blank" href="https://www.raywenderlich.com/5993-your-first-ios-app/lessons/1">watch this video on raywenderlich.com</a>. Ray Wenderlich’s website is an excellent resource for iOS in general.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/11NWKdEgqi660Qd0I14wXZXpUqr-783XV9R2" alt="Image" width="800" height="600" loading="lazy">
_Insights derived from data tend to deliver better results than gut feelings from founders. Photo by [Unsplash](https://unsplash.com/photos/1K6IQsQbizI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Franki Chamaki on &lt;a href="https://unsplash.com/search/photos/data?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-data-scientist">Data Scientist</h3>
<p><strong>What do they do?</strong></p>
<p>Data scientists help businesses solve problems through the processing of data. So what does that mean? A software engineer will implement some logging somewhere on a website or mobile app. This gets processed and eventually gets to the data scientists. The data scientists will then gather all these data points and derive insights from them.</p>
<p>We can use an e-commerce website as an example. After looking at a few different data points, a data scientist notices that only 0.5% of people that add an item to the cart end up making a purchase. The data scientist then hypothesizes that this could be the reason for the decline in revenue last month. They check the rate three months ago and see that it was at 5%.</p>
<p>It looks like that is probably the reason for the drop in revenue. They surface this to the right stakeholders. These stakeholders find out that there was a crash occurring during purchasing that caused the problem. This may not have been found if a data scientist didn’t work at the company.</p>
<p>Data scientists can also work to spot new paths to growth and ways to improve current products based off of data. <strong>The sky is the limit on how a data scientist can be leveraged at a company.</strong></p>
<p><strong>Why should I choose this career path?</strong></p>
<p>Become a data scientist if you love looking at data and trying to see patterns. Data scientists provide value by looking over data and trying to discover insights that will help their company grow. You have to love trying to come up with reasons for why specific patterns are occurring. You also have to have a deep understanding of the products you are working with, so you can vet hypotheses around your data insights.</p>
<p><strong>How do I get started?</strong></p>
<p>I would start with <a target="_blank" href="https://www.coursera.org/learn/decision-making?siteID=SAyYsTvLiGQ-qF51g6iB4QYpdQ7g0Fsh3g&amp;utm_content=10&amp;utm_medium=partners&amp;utm_source=linkshare&amp;utm_campaign=SAyYsTvLiGQ">this course on Coursera</a> which first gives you a better understanding of how data drives business decisions. If that course deepens your interest, start with <a target="_blank" href="https://medium.freecodecamp.org/i-ranked-all-the-best-data-science-intro-courses-based-on-thousands-of-data-points-db5dc7e3eb8e">this article</a> that recommends some great ways to start learning.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/682u2vw7Krtlkh2jFFdCymZdyjQfSP8es26l" alt="Image" width="800" height="1200" loading="lazy">
_Being a project manager requires maintaining a perfect balance between delivery date and quality. Photo by [Unsplash](https://unsplash.com/photos/flEStjHTY14?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Leio McLaren (@leiomclaren) on &lt;a href="https://unsplash.com/search/photos/balance?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-project-manager">Project Manager</h3>
<p><strong>What do they do?</strong></p>
<p>Project managers do exactly what their title implies, they manage products. But what exactly does that mean? Well, as a project manager, you need to have a high level view of the product you are working on.</p>
<p>You need to make sure everyone is executing and working on the most relevant tasks so you can ship your product on time. You need to understand what every person on the team is doing, how they’re doing it and when they’ll be done. You line up all the pieces so that the final product has everything it needs in the timeline you provided to the higher-ups.</p>
<p>This also means you need to help unblock people when they’re stuck. You need to organize meetings with other teams if you are dependent on them for finishing your product. You need to run sync up meetings for your team to ensure everyone is on track and not having issues.</p>
<p>The hardest part about being a project manager is ensuring that everything gets done on time and with quality. You also need to make sure the people on your team aren’t overwhelmed. This is always a delicate balance.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You are organized and love collaborating with others. You are able to balance the needs of many in order to deliver on a high quality product. You understand the trade off between time and quality and know when to push back for either.</p>
<p>Lets say the people waiting for your product demand that you finish it in 2 months when you know it will take 4 months to deliver a quality product. You must have the ability to provide convincing evidence for why you need the extra time. You also have to ensure that you don’t bow to pressure.</p>
<p><strong>Being a project manager requires maintaining a perfect balance between delivery date and quality.</strong></p>
<p>The opposite can be true also. Sometimes developers say that something will take 1 month when you’ve seen it done in 3 days before. You ask questions and find out that the developer wants to over-engineer this certain piece of work even though you know the product doesn’t need it. You have to figure out a way to get the developer to only build what is needed.</p>
<p>Like I said before, being able to work effectively with others while being organized and keeping a product on track is what it is all about. This is incredibly difficult. You need to have high level knowledge of a product but deep enough knowledge about every piece that you can keep people accountable for their work.</p>
<p><strong>How do I get started?</strong></p>
<p>A lot of project managers in tech use Agile and Scrum methodologies to organize their work. I would get started by looking into obtaining Scrum certifications. Take a look at the <a target="_blank" href="https://www.scrum.org/">Scrum website for more details.</a></p>
<p>Project manager’s tend to have a business administration degree or a project management degree. If you are already working on a computer science degree, you can consider getting a minor in one of these subject areas.</p>
<p>Another great way to get into project management is to manage a small project with your friends or an open source project. Practice makes perfect and real life application of project management skills will make you stand out as a candidate.</p>
<p>You can also start getting familiar with project management tools such as Trello, Jira, Quip, Excel and many more. Being familiar with the software a project manager uses will help you build your skills in project management.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/KjGOn6GcozEw3XKWvc5AYf-raga5A3PntdZa" alt="Image" width="800" height="1343" loading="lazy">
_Having a sleek front end is key in creating popular websites. Photo by [Unsplash](https://unsplash.com/photos/V09Io5ln-Qo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Aaron Huber on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-front-end-engineer">Front end engineer</h3>
<p><strong>What do they do?</strong></p>
<p>Front end engineers use HTML, CSS and JavaScript to build UI for websites. They focus on aspects that are important to the website such as accessibility, security, usability and performance. If you’ve ever logged into a website or bought something from an e-commerce store on your web browser, then you’ve interacted with a front end engineer’s code. <a target="_blank" href="https://medium.freecodecamp.org/my-role-as-a-front-end-web-engineer-explained-948d0f1ceac1">Check out this awesome article</a> for even more details.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>In a lot of ways, this job is similar to a mobile engineer’s job. They both build UI and should have a certain attention to detail when it comes to visual elements. They both work with designers to implement UI that is both performant and a delight to use. The main difference would be the languages and tools used and the fact that mobile developers are creating applications instead of websites.</p>
<p><strong>You should be a front end engineer if you are the kind of person that likes learning and using new languages and tech stacks</strong>. Being a front end engineer requires the use of HTML, CSS, JavaScript and SQL. On top of that, you will most likely need to know some back end server-side framework like Django, Ruby on Rails, or .Net.</p>
<p>Another reason to consider this path is if you are interested in problems around scaling. A mobile application will only ever serve one user at a time. This is due to the fact that only one person can use a mobile device at a time. A website has to serve potentially millions of people at the same time. This requires a different mindset and approach to prevent bottlenecks from occurring.</p>
<p><strong>How do I get started?</strong></p>
<p>This one is easy :) Just <a target="_blank" href="https://learn.freecodecamp.org/">checkout freeCodeCamp’s course</a>. This will give you all the skills you need to become a proficient front end engineer.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/Msen2gjqJuczr8xpH2q9txROYvhiiWRSnjwH" alt="Image" width="600" height="400" loading="lazy">
_From committed code to delivery to production, a DevOps engineer has got you covered. Photo by [Unsplash](https://unsplash.com/photos/0wsnJWonXFs?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="_blank" title=""&gt;Drew Beamer on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" rel="noopener" target="<em>blank" title=")</em></p>
<h3 id="heading-devops-engineer">DevOps Engineer</h3>
<p><strong>What do they do?</strong></p>
<p>This is by far the hardest role to explain. Because there is a lot of debate about whether this is really a role or actually just a mindset. The idea can be broken down into the fact that a DevOps engineer takes on both a developer and an operations job. Hence the term “DevOps”. Let’s look at each of these roles.</p>
<p>In general, software engineers want to build as many features as possible so they will look good to the higher ups. One of those new fancy features is bound to help the company grow which makes the software engineer look good.</p>
<p>An operations engineer wants stability. Which means they don’t want software engineers to release too many new features. Because with new features comes unpredictability. And with unpredictability, comes instability. The operations engineer just wants every new release to be stable. They want the release process to go smoothly. But releasing too many features or features of high risk threatens this goal, which is exactly what most software engineers are aiming to do.</p>
<p>These two roles obviously seem at odds but that is why a DevOps engineer can be so useful. <strong>A DevOps engineer can bridge the gap between development and operations</strong>. By doing this, they create meaningful communication routes between these sometimes silo-ed areas. A DevOps engineer creates a feature and sees it safely to production where it makes users satisfied. Being able to do this is highly valued at any company.</p>
<p><strong>Why should I choose this career path?</strong></p>
<p>You should choose this career path if you are not only interested in coding features, but want to learn about how to release your code to a production environment. You should have the drive to learn about every aspect of software engineering and release engineering.</p>
<p>You will most likely need years of experience to be termed as a “DevOps” engineer due to the vast amount of knowledge and tools you will need to learn. You should love learning new things. The idea of knowing every aspect of your tech stack should excite you. If you want to become the person that everyone goes to when something unexpected happens, then you should look into becoming a DevOps engineer.</p>
<p><strong>How do I get started?</strong></p>
<p>I’d get started by learning about how code gets released into a production environment for starters. This can be done by building your own website, and deploying it yourself. The best way is to work for a company for a while and work on every part of the deployment process. Volunteer to fix problems that others don’t want to deal with. That is a great way to learn.</p>
<p>Other than that, I’d recommend reading <a target="_blank" href="https://medium.com/@devfire/how-to-become-a-devops-engineer-in-six-months-or-less-366097df7737">this article on how to get into DevOps</a>. It is very well written gives even more actionable ways to become a DevOps engineer.</p>
<h3 id="heading-didnt-see-the-role-you-were-looking-for">Didn’t see the role you were looking for?</h3>
<p>If you enjoyed my summaries of these roles but didn’t see the role that you wanted, leave a comment! I will do another round of these career path overviews for the most clapped comments. Hopefully you enjoyed these summaries of these tech career paths. My hope is that you at least have a better understanding of the breadth of skills and knowledge it takes to release good tech to the world.</p>
<h4 id="heading-i-will-do-another-round-of-these-career-path-overviews-for-the-most-clapped-comments">I will do another round of these career path overviews for the most clapped comments.</h4>
<h3 id="heading-liked-what-you-read">Liked what you read?</h3>
<p><a target="_blank" href="https://medium.freecodecamp.org/how-i-went-from-stuck-and-hopeless-to-making-my-tech-career-dreams-come-true-d1fcf52c0650">Read about how I went from being a broke English teacher in Japan to working at a top tech company in just a few years!</a></p>
<p><a target="_blank" href="https://medium.freecodecamp.org/a-computer-science-degree-ticket-to-your-dream-tech-job-or-a-useless-piece-of-paper-ee488d27c384">Do you need a computer science degree to get a job in tech?</a></p>
<p><a target="_blank" href="https://medium.com/@colin.gabriel.smith/killing-it-during-your-first-tech-interview-16ce13f9d0ce">Passing your first tech interview: how to prepare.</a></p>
<p><a target="_blank" href="https://medium.freecodecamp.org/https-medium-com-colin-gabriel-smith-swift-vs-objective-c-5b19add8e2ed">Swift vs. Objective-C. How do they compare?</a></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ McDonald’s and Starbucks on Your Phone: Why Mobile Apps Are Now First on the Menu ]]>
                </title>
                <description>
                    <![CDATA[ By James Hsu One Friday this July, I got excited about McDonald's. So excited that I stopped at one before work in the morning and left with French fries and a coffee. Fries for breakfast. McDonald's had just announced that it would be giving out fre... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/why-mcdonalds-starbucks-are-all-in-on-native-mobile-apps-2faabc85b719/</link>
                <guid isPermaLink="false">66c366f2693ce41cd86e79a6</guid>
                
                    <category>
                        <![CDATA[ Apps ]]>
                    </category>
                
                    <category>
                        <![CDATA[ business ]]>
                    </category>
                
                    <category>
                        <![CDATA[ mobile ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ UX ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Mon, 24 Sep 2018 19:26:35 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*1qbKDuvqatJLhK_dSN8wlg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By James Hsu</p>
<p>One Friday this July, I got <em>excited</em> about McDonald's. So excited that I stopped at one before work in the morning and left with French fries and a coffee.</p>
<p>Fries for breakfast.</p>
<p>McDonald's had just announced that it would be giving out free medium fries every Friday with a minimum purchase of $1 through…</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
