<?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" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Farras Hafizhudin Indra Wijaya on Medium]]></title>
        <description><![CDATA[Stories by Farras Hafizhudin Indra Wijaya on Medium]]></description>
        <link>https://medium.com/@farras.hafizhudin?source=rss-abc69b449cfe------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*pHMIid8z1jyKrav3</url>
            <title>Stories by Farras Hafizhudin Indra Wijaya on Medium</title>
            <link>https://medium.com/@farras.hafizhudin?source=rss-abc69b449cfe------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 23 May 2026 15:08:11 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@farras.hafizhudin/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Refactoring & Design Pattern : Applications In Flutter Framework]]></title>
            <link>https://medium.com/@farras.hafizhudin/refactoring-design-pattern-applications-in-flutter-framework-d2bfb0c35e23?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/d2bfb0c35e23</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[repository-design-pattern]]></category>
            <category><![CDATA[refactoring]]></category>
            <category><![CDATA[repository-pattern]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Mon, 27 May 2024 19:51:52 GMT</pubDate>
            <atom:updated>2024-05-27T19:51:52.840Z</atom:updated>
            <content:encoded><![CDATA[<h3>Refactoring &amp; Design Pattern : Applications In Flutter Framework</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/490/0*hfxcyuoHXyfksF4Y.png" /><figcaption>Source : <a href="https://sdtimes.com/softwaredev/martin-fowler-revisits-refactoring/">Martin Fowler</a></figcaption></figure><p>In today’s standard of mobile application development, ensuring code maintainability, readability, and scalability is important. Refactoring and design patterns provide structured approaches to improve these aspects. We will dive in deeper into the application of Martin Fowler’s refactoring and design pattern within our Flutter application.</p><h3>Main Aspects Of Refactoring</h3><p>Refactoring is the process of restructuring existing code without any kind of change of its original external behavior. The main goal of refactoring is to improve the nonfunctional attributes of the software.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/656/1*q_B1ius2BvV45mPSkvFliA.png" /><figcaption>Source : <a href="https://refactoring.guru/refactoring">Refactoring Guru</a></figcaption></figure><p>Here are the key points to understand about refactoring:</p><ol><li><strong>Code Quality Improvements:</strong> Enhances the internal structure of the code, making it more somewhat readable, maintainable, and scalable in the long run.</li><li><strong>Zero Change In Code Behavior:</strong> While the internal structure of the code is improved, its external behavior — how the code functions and what it does — remains unchanged as if it were not tampered at first glance.</li><li><strong>Incremental Changes:</strong> Involves incremental changes compared to larger scale overhauls. This makes the process safer and easier to manage.</li><li><strong>Automated Testing:</strong> Having a comprehensive suite of tests without introducing new bugs and the main code’s functionality remains consistent.</li></ol><h3>Design Patterns And Common Uses</h3><p>Design patterns have been proven to be reusable solutions to common problems that occur in most software designs. They provide “templates” on how to solve these problems in a way that has been effective for others with the same use cases. Design patterns help to improve code readability and reduce complexity for easier collaboration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/488/1*j1kaUQFn7gAq7o3Ub6dLAQ.png" /><figcaption>Source : <a href="https://refactoring.guru/design-patterns">Refactoring Guru</a></figcaption></figure><p>Some design patterns can be categorized into few types or kinds:</p><ol><li><strong>Repository Pattern:</strong> Separates the logic that retrieves data from the main business logic, providing somewhat modular and testable approach to accessing data.</li><li><strong>Service Layer:</strong> Defines an application’s boundary tad-bits and encapsulates its business logic.</li><li><strong>Factory Pattern:</strong> Provides an interface for creating objects in a superclass but allows subclasses to tamper the type of objects that will be created.</li><li><strong>Data Transfer Object (DTO):</strong> An object that carries data between processes to reduce the number of method calls.</li><li><strong>Decorator Pattern:</strong> Allows behavior to be added to an individual object without affecting the behavior of other objects from the same class.</li><li><strong>Singleton Pattern:</strong> Ensures a class has only one instance and provides a global point of access to it.</li></ol><h3><strong>Applications Approaches In Flutter Framework</strong></h3><p>In our recent flutter app, we were dealing with an academic conferences services that lets user gain access to conference schedules, speakers, academic publications, and so on. So we stumbled upon a pattern called Repository that fits somewhat perfectly for this use cases.</p><p>The Repository pattern helps us to abstract and encapsulate data access logic, making our code easier to work on and test. Hence these are why we think it fits well to our current architecture:</p><ul><li><strong>Separation of Concerns:</strong> It separates the data access logic from the main business logic, making the application easier to manage and test.</li><li><strong>Flexibility:</strong> It allows for easy swapping of data sources without changing the main business logic.</li><li><strong>Testability:</strong> By abstracting the data layer, we were able to mock the repository during unit tests, leading to better test coverage.</li></ul><h3>Overview of the Flutter Application Structure</h3><ul><li><strong>Model:</strong> Defines the data structure.</li><li><strong>Repository:</strong> Manages data fetching and storage.</li><li><strong>User Interface:</strong> Presents the data to the user through a mobile interface.</li></ul><p>To illustrate these concepts, we will examine one of our venue map pages for the conference. The components include:</p><ul><li><strong>venue_map_model.dart:</strong> Represents the structure of our venue map data. It includes fields for the ID, place, and image URL.</li></ul><pre>class VenueMap {<br>  String id;<br>  String place;<br>  String image;<br><br>  VenueMap({<br>    required this.id,<br>    required this.place,<br>    required this.image,<br>  });<br><br>  factory VenueMap.fromJson(Map&lt;String, dynamic&gt; json) =&gt; VenueMap(<br>    id: json[&#39;id&#39;],<br>    place: json[&#39;place&#39;],<br>    image: json[&#39;image&#39;] ?? &#39;&#39;,<br>  );<br>}</pre><ul><li><strong>venue_map_repository.dart:</strong> Responsible for fetching the venue map data from a remote server and storing it locally.</li></ul><pre>import &#39;dart:convert&#39;;<br>import &#39;package:http/http.dart&#39; as http;<br>import &#39;package:konfui_mobile/view_venue_map/venue_map_model.dart&#39;;<br><br>class VenueMapRepository {<br>  List&lt;VenueMap&gt; venueMaps = [];<br><br>  Future&lt;List&lt;VenueMap&gt;&gt; getVenueMaps() async {<br>    var url = Uri.parse(&#39;URL&#39;);<br>    var response = await http.get(<br>      url,<br>      headers: {<br>        &quot;Access-Control-Allow-Origin&quot;: &quot;*&quot;,<br>        &quot;Content-Type&quot;: &quot;application/json&quot;,<br>      },<br>    );<br>    if (response.statusCode == 200) {<br>      var fetchedJsonDataList = json.decode(response.body)[&quot;data&quot;];<br>      for (var venueMap in fetchedJsonDataList) {<br>        venueMaps.add(VenueMap.fromJson(venueMap));<br>      }<br>      return venueMaps;<br>    } else {<br>      throw Exception(&#39;Failed to load Venue Maps&#39;);<br>    }<br>  }<br><br>  VenueMap getByPlace(String place) {<br>    if (venueMaps.isNotEmpty) {<br>      for (VenueMap venueMap in venueMaps) {<br>        if (venueMap.place == place) {<br>          return venueMap;<br>        }<br>      }<br>    }<br>    throw Exception(&quot;$place currently does not have a venue map&quot;);<br>  }<br>}</pre><ul><li><strong>view_venue_map.dart:</strong> Displays the venue map and handles user interactions.</li></ul><pre>import &#39;package:flutter/material.dart&#39;;<br>import &#39;package:konfui_mobile/venue_map_rooms/venue_map_room_model.dart&#39;;<br>import &#39;package:konfui_mobile/venue_map_rooms/venue_map_room_repository.dart&#39;;<br>import &#39;package:konfui_mobile/view_venue_map/venue_map_model.dart&#39;;<br>import &#39;package:konfui_mobile/view_venue_map/venue_map_repository.dart&#39;;<br>import &#39;package:photo_view/photo_view.dart&#39;;<br>import &#39;package:widget_zoom/widget_zoom.dart&#39;;<br><br>class ViewVenueMapPage extends StatelessWidget {<br>  VenueMapRepository venueMaps = VenueMapRepository();<br>  final String place;<br><br>  ViewVenueMapPage({super.key, required this.place});<br><br>  @override<br>  Widget build(BuildContext context) {<br>    return FutureBuilder&lt;List&lt;VenueMap&gt;&gt;(<br>      future: venueMaps.getVenueMaps(),<br>      builder: (context, snapshot) {<br>        if (snapshot.connectionState == ConnectionState.waiting) {<br>          return const Center(child: CircularProgressIndicator());<br>        } else if (snapshot.hasError) {<br>          return const Center(child: Text(&quot;Error: Couldn&#39;t fetch Venue Map\nCheck your connection and refresh&quot;));<br>        } else {<br>          try {<br>            final VenueMap venueMap = venueMaps.getByPlace(place);<br>            return WidgetZoom(<br>              heroAnimationTag: &#39;tag&#39;,<br>              zoomWidget: Image.network(<br>                venueMap.image,<br>                fit: BoxFit.contain,<br>              ),<br>            );<br>          } catch (e) {<br>            return Container(<br>              height: 200,<br>              color: Colors.grey,<br>              alignment: Alignment.center,<br>              child: const Text(<br>                &quot;Venue Map not found&quot;,<br>                style: TextStyle(color: Colors.white, fontSize: 20),<br>              ),<br>            );<br>          }<br>        }<br>      },<br>    );<br>  }<br>}<br><br>Future&lt;List&lt;dynamic&gt;&gt; fetchData() async {<br>  VenueMapRepository venueMaps = VenueMapRepository();<br>  VenueMapRoomRepository venueMapRoomRepository = VenueMapRoomRepository();<br><br>  List&lt;dynamic&gt; results = await Future.wait([<br>    venueMaps.getVenueMaps(),<br>    venueMapRoomRepository.getVenueMapRooms(),<br>  ]);<br><br>  return results;<br>}</pre><ul><li>The <strong>showVenueMapPopup</strong> function displays a popup with venue map details.</li></ul><pre>void showVenueMapPopup(BuildContext context, String place) {<br>  showDialog(<br>    context: context,<br>    builder: (BuildContext context) {<br>      return FutureBuilder&lt;List&lt;dynamic&gt;&gt;(<br>        future: fetchData(),<br>        builder: (BuildContext context, AsyncSnapshot&lt;List&lt;dynamic&gt;&gt; snapshot) {<br>          if (snapshot.connectionState == ConnectionState.waiting) {<br>            return const Center(child: CircularProgressIndicator());<br>          } else if (snapshot.hasError) {<br>            return const Center(child: Text(&quot;Error: Couldn&#39;t fetch data\nCheck your connection and refresh&quot;));<br>          } else {<br>            List&lt;VenueMap&gt; venueMaps = snapshot.data![0] as List&lt;VenueMap&gt;;<br>            List&lt;VenueMapRoom&gt; venueMapRooms = snapshot.data![1] as List&lt;VenueMapRoom&gt;;<br><br>            try {<br>              final VenueMap venueMap = venueMaps.firstWhere((map) =&gt; map.place == place);<br>              final List&lt;VenueMapRoom&gt; filteredRooms = venueMapRooms.where((room) =&gt; room.venueMapId == venueMap.id).toList();<br><br>              return AlertDialog(<br>                content: SingleChildScrollView(<br>                  child: Column(<br>                    crossAxisAlignment: CrossAxisAlignment.start,<br>                    children: [<br>                      ViewVenueMapPage(place: place),<br>                      const SizedBox(height: 12),<br>                      const Text(<br>                        &#39;Rooms:&#39;,<br>                        style: TextStyle(<br>                          fontWeight: FontWeight.bold,<br>                          fontSize: 12,<br>                        ),<br>                      ),<br>                      const SizedBox(height: 6),<br>                      Column(<br>                        crossAxisAlignment: CrossAxisAlignment.start,<br>                        children: filteredRooms.map((room) {<br>                          return ListTile(<br>                            leading: const Icon(Icons.house_rounded),<br>                            title: Text(&quot;Nama Ruang : ${room.room}&quot;),<br>                            subtitle: Text(&quot;Nomor Ruang : ${room.label}&quot;),<br>                          );<br>                        }).toList(),<br>                      ),<br>                    ],<br>                  ),<br>                ),<br>                actions: &lt;Widget&gt;[<br>                  TextButton(<br>                    onPressed: () {<br>                      Navigator.of(context).pop();<br>                    },<br>                    child: const Text(&#39;Close&#39;),<br>                  ),<br>                ],<br>              );<br>            } catch (e) {<br>              return AlertDialog(<br>                title: Text(place),<br>                content: Container(<br>                  height: 200,<br>                  color: Colors.grey,<br>                  alignment: Alignment.center,<br>                  child: const Text(<br>                    &quot;Venue Map not found&quot;,<br>                    style: TextStyle(color: Colors.white, fontSize: 20),<br>                  ),<br>                ),<br>                actions: &lt;Widget&gt;[<br>                  TextButton(<br>                    onPressed: () {<br>                      Navigator.of(context).pop();<br>                    },<br>                    child: const Text(&#39;Close&#39;),<br>                  ),<br>                ],<br>              );<br>            }<br>          }<br>        },<br>      );<br>    },<br>  );<br>}</pre><h3><strong>Conclusions</strong></h3><p>Refactoring and applying design pattern in your current project provides a robust and maintainable structure for managing data access. With the addition of Repository Pattern, allows us to encapsulate the data retrieval logic within our dedicated repository classes. At this point, we’ve achieve a clear separation of concerns, enhancing code readability and maintainability.</p><p>This pattern not only facilitates easier unit testing by allowing for mock implementations but also offers the flexibility to swap data sources with minimal changes to the main business logic. Consequently, the Repository pattern fits perfectly to our current Flutter application, promoting a cleaner and more scalable codebase.</p><p><em>Sources : </em><a href="https://refactoring.guru/"><em>Refactoring Guru</em></a><em> | </em><a href="https://sdtimes.com/softwaredev/martin-fowler-revisits-refactoring/"><em>SD Times</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2bfb0c35e23" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Enhancing Teamworks In Software Engineering Using Collaborative Tools]]></title>
            <link>https://medium.com/@farras.hafizhudin/enhancing-teamworks-in-software-engineering-using-collaborative-tools-719b853dd866?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/719b853dd866</guid>
            <category><![CDATA[teamwork]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[teamwork-project]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Mon, 27 May 2024 14:32:25 GMT</pubDate>
            <atom:updated>2024-05-27T14:32:25.114Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*xKAn1c4qIJig_rJ8" /><figcaption>Source : <a href="https://www.linkedin.com/pulse/teamwork-right-tools-people-practices-bi-plus?trk=articles_directory">Linkedin</a></figcaption></figure><p>In today’s fast-paced software engineering landscape, effective teamwork is pivotal for delivering products on time. Nowadays, collaboration tools have become essential in building up team communications, coordinations, and productivity. In my latest software engineering team, we utilized a combination of Discord, GitLab, and Miro to streamline our workflow and notify our latest addition over product changes and new features updates.</p><h3><strong>What Are Collaboration Tools And What Distinguish Them One And Another</strong>?</h3><p>Generally, collaboration tools vary widely in functionality and purposes, they might offer a combination of the following key features:</p><ol><li><strong>Communication:</strong> Enable real-time or asynchronous communication, including text messaging, voice &amp; video calls, and discussion text channels or forums.</li><li><strong>File Attachment and Management:</strong> Capabilities for storing, sharing, and editing project-related documents and files.</li><li><strong>Project Management:</strong> Features for tracking tasks, deadlines, milestones, and project progress.</li><li><strong>Version Control:</strong> Systems that manage changes to documents or code, allowing multiple users to work on a project simultaneously with the options such as version rollbacks.</li><li><strong>Integration:</strong> Ability to connect with other tools and services, creating a seamless workflow.</li><li><strong>Visual Collaboration:</strong> Tools that support brainstorming and planning through visual elements like whiteboards, sticky notes, and diagrams.</li></ol><h3>Communication and Instant Notifications with Discord</h3><p>Discord, notoriously known as a platform for video game communities, at its core is also a versatile communication tool for team. It offers real-time messaging, voice channels, and extensive customization options make it ideal for such software engineering teams.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1009/1*JlyYcxqeQ01oKegAiCxNlw.png" /><figcaption>PPL A6’s Discord’s Gitlab Notification Webhooks</figcaption></figure><blockquote>We integrated Discord with GitLab using webhooks, which allowed us to receive instant notifications for pull requests (PR), merge requests (MR), commits, and merging activities directly in our designated channels. This integration ensured that everyone on the team was immediately aware of changes in the codebase, facilitating quicker reviews and reducing the turnaround time for feedback.</blockquote><p>Key benefits of using Discord included:</p><ul><li><strong>Real-time Communication:</strong> Send messages and voice channels allowed for quick discussions and resolutions of issues.</li><li><strong>Centralized Notifications:</strong> Receive GitLab’s notifications directly into Discord in order to avoid the constant needs to check GitLab for updates, ensuring that no critical updates were missed.</li><li><strong>Collaboration Channels:</strong> Separate channels for different text channels and topics in order to keep conversations organized, making it easier to track and retrieve information.</li></ul><h3>Code Management and Collaboration with GitLab</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BVwqXr1nkcQ3390PSNqaRw.png" /><figcaption>PPL A6’s Mobile Merge Requests</figcaption></figure><p>GitLab act as our primary platform for version control, offering a Git based central commands with continuous integration/continuous deployment (CI/CD) and collaborative code reviews.</p><p>GitLab offer us things such as:</p><ul><li><strong>Merge Requests and Code Reviews</strong>: Structured code review and feedbacks through assignee’s merge requests allowed for cooperatives code changes, ensuring good standards and knowledges among team.</li><li><strong>CI/CD Pipelines</strong>: Automated testing and deployment pipelines helps our development cycle such as maintain our code reliability &amp; performance.</li><li><strong>Issue Tracking</strong>: GitLab’s issue tracking system helped us manage tasks, bugs, and feature requests effectively, aligning our development efforts with project goals.</li></ul><h3>Visual Collaboration and Sprint Planning with Miro</h3><p>Miro is a digital whiteboard/sticky notes platform, played a pivotal role in our sprint planning sessions. Its simplified interface and set of features enabled us to visualize our plans and ideas collaboratively, regardless of team members whereabouts.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KslbX2ocjyqiw_DFPJg3wA.png" /><figcaption>PPL A6’s Miro Sprint Planning Board</figcaption></figure><p>Miro offers few primary elements including:</p><ul><li><strong>Interactive Sprint Planning:</strong> We were able to create and manage sprint boards, allowing everyone to contribute to planning sessions in real-time. This visual approach made it easier to prioritize tasks, define product backlog items and allocate resources effectively.</li><li><strong>Ideation And Brainstorming:</strong> Miro’s flexibility allowed us to perform brainstorming sessions, taking ideas on sticky notes, and organizing them into sticky cards filled with backlog descriptions and workflows.</li><li><strong>Documentation and Mapping:</strong> We documented user stories and other critical project components to be able to provide a centralized visual reference that was accessible to all team members with ease.</li></ul><h3>Conclusion</h3><p>The combination of Discord, GitLab, and Miro proved to be pretty effective in enhancing our teamwork and productivity. Discord’s real-time communication and notifications, GitLab’s robust code management and CI/CD capabilities, and Miro’s interactive planning and collaboration features created a seamless workflow that supported our software development efforts.</p><p>With us leveraging these tools, we were able to maintain communication, streamline our development processes, and foster a collaborative environment that try to empowered every team member to contribute evenly and effectively.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=719b853dd866" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Maximizing NodeJS Performances with Sentry.io Platform Monitoring Services]]></title>
            <link>https://medium.com/@farras.hafizhudin/maximizing-nodejs-performances-with-sentry-io-platform-monitoring-services-76e51a3f24e5?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/76e51a3f24e5</guid>
            <category><![CDATA[platform-monitoring]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[performance-monitoring]]></category>
            <category><![CDATA[error-tracking]]></category>
            <category><![CDATA[sentryio]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Mon, 27 May 2024 13:22:55 GMT</pubDate>
            <atom:updated>2024-05-27T13:22:55.485Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*7oFl09PZi0EQscDi.png" /><figcaption>Source : <a href="https://sentry.io/welcome/">Sentry.io</a></figcaption></figure><p>We as software developers, often times stumble upon both analyzing and addressing not only errors but also other in-app performances. Since some of those tasks can sound a bit daunting and tedious at the same time. Sentry offers real-time error tracking, performance monitoring and analytics, complete with insights into what is currently happening ith our application.</p><p>Integrating Sentry.io with NodeJS can significantly enhances the ability to detect, diagnose, and fix issues quickly, ensuring a more reliable app performance. We’ll dive in deeper into Sentry.io as a monitoring and error tracking tool that helps identify and resolve those issues within our application.</p><h3><strong>Setting Up Sentry With Our NodeJS App</strong></h3><ol><li>Head over to <strong>Sentry.io</strong> and <strong>sign in</strong> a new account.<strong> Create a new project</strong> based on the platform you are currently developing with.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2gLiYkOHoPjb5X1yTnt0wQ.png" /><figcaption>Sentry.io Studio</figcaption></figure><p>2. <strong>Install Sentry’s SDK in your app directory</strong>. Since we are trying to integrate with NodeJS, we can proceed using npm as our package manager.</p><pre>npm install --save @sentry/node @sentry/profiling-node @sentry/tracing</pre><p>3. <strong>Configure Your Sentry’s DSN &amp; Initialize Sentry’s SDK</strong>. Here are the approach with my current NodeJS app.</p><pre># Best to set your DSN in dotenv for good practices<br>DSN=YOUR_SENTRY_IO_DSN</pre><pre>require(&#39;dotenv&#39;).config();<br>const sentry = require(&#39;@sentry/node&#39;);<br>const { nodeProfilingIntegration } = require(&#39;@sentry/profiling-node&#39;);<br><br>sentry.init({<br>  dsn: process.env.DSN,<br>  integrations: [nodeProfilingIntegration()],<br>  tracesSampleRate: 1.0,<br>  profilesSampleRate: 1.0<br>});</pre><p>4. <strong>Start Using Sentry’s Transaction &amp; Span</strong>. What are those?</p><ul><li><strong>Transaction </strong>is a representation of a series of operations or events that occur in a specific sequence within your application. It typically starts when a request is received and ends when a response is sent, encompassing all the steps in between. Transactions provide an overview of the performance of these operations and help identify where delays might be occurring.</li><li><strong>Span</strong> is a single unit of work within a transaction. It represents a specific operation, such as a database query, an HTTP request, or any other task. Spans are used to break down transactions into smaller parts, allowing you to see the detailed timing and performance of each individual operation within the broader transaction.</li></ul><p>I will be using Sentry’s Span in my app case for a cloud function called “getEvents()”, which returns List&lt;Events&gt; from corresponding Google Spreadsheet.</p><pre>exports.getEvents = functions.region(REGION).https.onRequest(<br>    async (request, response) =&gt; {<br>      try {<br>        const apiKey = functions.config().gsheet.apikey;<br>        const sheetService = new GoogleSheetService(apiKey);<br>        const eventsData = await sheetService.getEvents();<br>        response.status(HttpStatus.StatusCodes.OK).type(JSON_TYPE).send({<br>          data: eventsData,<br>        });<br>      } catch (error) {<br>        response.status(HttpStatus.StatusCodes.INTERNAL_SERVER_ERROR).send({<br>          error: &quot;Unable to connect with Google Spreadsheet&quot;,<br>        });<br>        <br>        sentry.startSpan(<br>          {<br>            op: &#39;Google API Request&#39;,<br>            name: &#39;getEvents()&#39;,<br>          },<br>          () =&gt; {<br>            setTimeout(() =&gt; {<br>              try {<br>                console.log(&quot;Google&#39;s API Request failed on getEvents() called&quot;);<br>              } catch (e) {<br>                sentry.captureException(e);<br>              }<br>            }, 99);<br>          }<br>        );<br>      }<br>    },<br>);</pre><p>With this approach, everytime “getEvents()” is called, sentry will start a span full with its own stack trace and catch any exception errors to capture and display it on the Sentry’s Studio.</p><p>5. <strong>Start analyzing</strong> any issues regarding your platform.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IqLC_Qf--BLqWmUzLjiXfA.png" /><figcaption>Sentry.io Studio</figcaption></figure><p>Here we have a “ReferenceError” issue with stack tracing that “Sentry” is undefined, indicating either that the package was not installed properly or it was improperly imported. From this point onwards, we will be given notifications on any kinds of issues regarding with platform we are currently developing with.</p><h3><strong>Other Sentry’s Services That You Might Be Interested To Use With</strong></h3><p>Let’s talk about the other services that Sentry has to offer.</p><ol><li><strong>Configure Performance Monitoring</strong></li></ol><pre>Sentry.init({<br>  dsn: process.env.DSN,<br>  integrations: [<br>    new Sentry.Integrations.Http({ tracing: true }),<br>    new Tracing.Integrations.Express({ app }),<br>  ],<br>  tracesSampleRate: 1.0,<br>});<br><br>app.use(Sentry.Handlers.requestHandler());<br>app.use(Sentry.Handlers.tracingHandler());</pre><pre>app.get(&#39;/api/data&#39;, async (req, res) =&gt; {<br>  const transaction = Sentry.startTransaction({ name: &#39;fetchData&#39; });<br>  try {<br>    const data = await fetchDataFromDatabase();<br>    res.json(data);<br>  } catch (error) {<br>    Sentry.captureException(error);<br>    res.status(500).send(&#39;Internal Server Error&#39;);<br>  } finally {<br>    transaction.finish();<br>  }<br>});</pre><p>With Sentry’s transaction, you can create custom operations within your application to trace the flow and measure the time taken for each of these operation.</p><p>2. <strong>Better Insights With Contexts</strong></p><pre>Sentry.setUser({ id: &#39;1234&#39;, email: &#39;user@example.com&#39; });<br>Sentry.setTag(&#39;feature-flag&#39;, &#39;new-dashboard&#39;);<br>Sentry.setExtras({ section: &#39;homepage&#39;, action: &#39;click&#39; });</pre><ul><li><strong>Sentry.setUser()</strong> associates a specific user with the error or event being tracked. By providing user details such as id and email, you can identify which users are affected by certain issues. This is particularly useful for debugging user-specific problems and improving customer support.</li><li><strong>Sentry.setTag()</strong> attaches a tag to the error or event. Tags are key-value pairs that categorize and filter issues based on specific criteria. For example, tagging errors with a feature-flag can help you determine if issues are related to a particular feature or experiment in your application. This aids in quickly identifying patterns and assessing the impact of new features.</li><li><strong>Sentry.setExtras()</strong> adds arbitrary data to the error or event, providing more context about the application’s state when the issue occurred. setExtras() allows you to include detailed information about the environment, actions performed, or any other relevant data that can assist in reproducing and understanding the problem. In this example, it specifies that the user was on the homepage and performed a click action.</li></ul><h3><strong>Conclusion</strong></h3><p>Integrating Sentry.io with NodeJS application is one way to track errors and monitor performance. Sentry facilitates real-time insights and in-depth analytics, which aid in the better functioning of a highly reliable and performant solution. Be it unexpected errors or bottlenecks in performance, Sentry.io offers us developers with the tools necessary for such problems.</p><p><em>Sources : </em><a href="https://docs.sentry.io/"><em>Sentry.io documentation</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76e51a3f24e5" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How To Conduct UX Research & Usability Testing Using Maze]]></title>
            <link>https://medium.com/@farras.hafizhudin/how-to-conduct-ux-research-usability-testing-using-maze-d939ffa4dcde?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/d939ffa4dcde</guid>
            <category><![CDATA[user-experience]]></category>
            <category><![CDATA[usability-testing]]></category>
            <category><![CDATA[ux]]></category>
            <category><![CDATA[ux-research]]></category>
            <category><![CDATA[user-experience-research]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Sun, 24 Mar 2024 14:45:15 GMT</pubDate>
            <atom:updated>2024-03-24T14:47:03.168Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/511/0*0_cp1qPy2r6GjIs5" /><figcaption>Source : <a href="https://maze.co/">Maze</a></figcaption></figure><p>In software development, creating products and services that meet user’s needs and expectations is crucial. User Experience research and usability testing does take parts on this process, allowing both designers and developers to understand user behavior, preferences, and pain points.</p><p>Maze, a powerful web application tool designed specifically for UX research and usability testing, offers and act as platform to streamline these processes and extract insights. In this article, we’ll dive in deeper and explore how to conduct UX research and usability testing using Maze.</p><h3><strong>Setting Up User Interfaces For Testing</strong></h3><ol><li><strong>Define Objectives</strong></li></ol><p>Before diving even further, we define the objectives. What are you trying to learn or validate? Establishing clear goals will guide the entire testing process.</p><p>In my current development team, we have a task to rebuild mainly a mobile application for academic conferences, thus guiding us to create such environment and interfaces proprietary to our requirements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/222/1*ookKEO95PV9xpgW8R9JW0w.png" /><figcaption>Figma Environment</figcaption></figure><p><strong>2. Create Prototypes</strong></p><p>Utilize design tools like Figma to create interactive prototypes of your digital product. Maze infact does supports various prototype formats.</p><p>Our team approach takes with Low &amp; High Fidelity Prototypes to further set it up for usability testing later on.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YWvRR4q4tQdV9OFUfG5fKA.png" /><figcaption>Design Prototypes</figcaption></figure><p><strong>3. Configure Test Settings</strong></p><p>Customize such participant demographics, device types, and testing environments to ensure that your tests align with your target audience and objectives.</p><p>Since our scope takes place on mobile, we try to imitate a lot of scrollable pages and etc.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/412/1*TuQxG211B4P-ZWr2V_hoRg.png" /><figcaption>Mobile with on app screen like prototype</figcaption></figure><h3>Conduct &amp; Analyze Usability Test</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zss8hnQvDFTzOhIH1Mig7w.png" /></figure><ol><li>Head to Maze and conduct a new study, whether its individually or inside a project scopes.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kMkjUgpvZBpsdjbAJNkZtA.png" /></figure><p>2. Up next, we can link and add our prototype to set its preview and start configuring our path for further usability testing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YMyVbCn7gW4zt_ytY0jLtg.png" /></figure><p>3. Share our maze path to our testers, whether you have a dedicated team for one or anyone that can help out!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8KIRu0SqzIGy3vvDBvwWQw.png" /></figure><p>4. Analyze each path that our testers take and evaluate on why and how does these people navigate through each different pages. Track the impact of design iterations on user behavior and satisfaction through these subsequent usability tests. Monitor metrics over time to gauge improvements and identify areas for further enhancement.</p><h3><strong>Summary</strong></h3><p>By leveraging Maze for UX research and usability testing, both designers and developers can gain valuable insights into user behavior and preferences, leading to more user-centric and successful digital products.</p><p>With its user-friendly interface and robust features, Maze empowers teams to iterate with confidence, delivering exceptional experiences that resonate with users. Incorporate Maze into your UX toolkit and unlock the full potential of designs process.</p><p><em>Source &amp; Reference : </em><a href="https://maze.co/"><em>Maze | The Continuous Product Discovery Platform</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d939ffa4dcde" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Software Quality Assurance Using SonarQube As An Analysis Tool]]></title>
            <link>https://medium.com/@farras.hafizhudin/software-quality-assurance-using-sonarqube-as-an-analysis-tool-0648f97d76ea?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/0648f97d76ea</guid>
            <category><![CDATA[sonarscanner]]></category>
            <category><![CDATA[sonarqube]]></category>
            <category><![CDATA[quality-assurance]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Tue, 05 Mar 2024 11:15:55 GMT</pubDate>
            <atom:updated>2024-03-05T11:15:55.239Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*vjWG8LZSTASV6fMR.png" /><figcaption>Source : <a href="https://www.google.com/url?sa=i&amp;url=https%3A%2F%2Fmedium.com%2F%40mrdevsecops%2Fintroduction-to-sonarqube-and-its-features-27c2e030068a&amp;psig=AOvVaw0rY8-XzZE6fzDsLVv7EumB&amp;ust=1709720161268000&amp;source=images&amp;cd=vfe&amp;opi=89978449&amp;ved=0CBQQjhxqFwoTCLCmkYny3IQDFQAAAAAdAAAAABAH">Introduction to SonarQube and Its Features</a></figcaption></figure><p>Software Quality Assurance (SQA) plays a pivotal role in implementing methodologies that serves as a tool to detect bugs and vulnerabilities early in software development lifecycle. One of the recent tools that has gained significant popularity is SonarQube.</p><p>SonarQube is a platform that provides continuous inspection of code quality to perform automatic reviews with static analysis of code to detect bugs, code smells, and security vulnerabilities. In this article, we’ll dive in deeper and explore how it serves me in my current software development team as a powerful analysis tool in Software Quality Assurance.</p><h3><strong>Overview</strong></h3><p>SonarQube offers a wide range of features. It provides near real-time feedback on code quality and security vulnerabilities, providing insights for maintaining standards throughout the development process. Some key features include:</p><ol><li><strong><em>Static Code Analysis:</em></strong> Performs static code analysis to identify quality-related issues.</li><li><strong><em>Code Coverage:</em></strong> Measures code coverage ensuring the identification of each features that need further additional testing.</li><li><strong><em>Technical Debt Management:</em></strong> Calculates technical debt to fix issues identified in the codebase, enabling teams to prioritize and address them proficiently.</li><li><strong><em>Integration with CI/CD Pipelines:</em></strong> Seamlessly integrates with Continuous Integration/Continuous Deployment pipelines, allowing for automated code analysis and feedback in software development.</li></ol><h3><strong>Configuring &amp; Integrating SonarQube To CI/CD Pipelines</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EqUJqtuDEVcsmw5Idjv-6w.png" /><figcaption>CSUI SonarQube Instance</figcaption></figure><p>Navigate to your SonarQube instance and add a new project repository.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yZ5SxcsGQsVAbAWwvEtbhg.png" /></figure><p>Select any git project / repositories that you want to set up for further configuration &amp; integration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/668/1*gMdYTzbUgCrDtEOKjQkJGw.png" /></figure><p>SonarQube will ask for your access token and you can proceed with running the sonar scanner for analyzing on your handpicked project. Read more about it <a href="https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/"><strong>here</strong></a>. After that, we are more or less ready to integrate it with our CI/CD pipelines.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q46IlNTegOV62LEbzJeW3w.png" /><figcaption>SonarQube CLI for gitlab-ci</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/891/1*JXcI4Cb5py97ltQ9LKE8kQ.png" /><figcaption>GitLab Environment Variables</figcaption></figure><p>As shown above, i am going to add a new stage called “sonarqube-check” to run its cli complete with each scripts needed for sonar to be able to sent its review to our SonarQube instance. Don’t forget to set up environment variables as per best practices to ensure software security measures. For further information about SonarQube Integration CLI you can read it <a href="https://docs.sonarsource.com/sonarqube/9.8/devops-platform-integration/gitlab-integration/"><strong>here</strong></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/727/1*Mkc11jrAnLRcPqWtH5XeYw.png" /><figcaption>Pipeline jobs succeeded</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vvVOnhLxnluuFR20RnWVLQ.png" /><figcaption>Freshly created sonarqube instance</figcaption></figure><p>From here, we can start to view and navigate issues related to our selected project, such as bugs, vulnerabilities, code smells, etc. We also can review issues and mark them as redudant if anything seems like a false positive/negative of what sonar has analyzed beforehand.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fWIKeZ5fjL9a1BEJKGJNZg.png" /><figcaption>Resolving issues, example taken from my Advanced Programming course</figcaption></figure><h3><strong>Conclusion</strong></h3><p>SonarQube acts as a powerful analytical tool in software quality assurance, providing a wide range of features to identify and improve code quality, security, and maintainability. The seamless integration to CI/CD pipelines also provides such improvement that enable us to identify and address issues.</p><p><em>Source &amp; Reference : </em><a href="https://docs.sonarsource.com/sonarqube/latest/"><em>SonarQube Documentation</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0648f97d76ea" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SOLID Principle And Its Implementation In NodeJS]]></title>
            <link>https://medium.com/@farras.hafizhudin/solid-principle-and-its-implementation-in-nodejs-b51c5f80fdbb?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/b51c5f80fdbb</guid>
            <category><![CDATA[solid-principles]]></category>
            <category><![CDATA[nodejs]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Tue, 05 Mar 2024 08:55:34 GMT</pubDate>
            <atom:updated>2024-03-05T08:56:29.806Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/843/0*6b9QSm5dycf2cSO1.png" /><figcaption>Source : <a href="https://www.geeksforgeeks.org/single-responsibility-in-solid-design-principle/">Single Responsibility in SOLID Design Principle</a></figcaption></figure><p>SOLID principles are considered fundamental appliances for writing clean, maintainable, and scalable within a codebase. These principles were introduced in order to aid developers in creating softwares that are understandable, flexible, and robust. In this article, we’ll dive in deeper about what are the SOLID principles and how they can be effectively implemented within my current NodeJS project.</p><h3><strong>Overview</strong></h3><blockquote>SOLID stands for five design principles:</blockquote><blockquote>1. Single Responsibility Principle (SRP)<br>2. Open/Closed Principle (OCP)<br>3. Liskov Substitution Principle (LSP)<br>4. Interface Segregation Principle (ISP)<br>5. Dependency Inversion Principle (DIP)</blockquote><p>Let’s dive right into each of these principles.</p><ul><li><strong><em>Single Responsibility Principle (SRP):</em></strong><br>Each module or class should have a single job, either in terms of responsibility or functionality. SRP adherence makes the code more modular, easy to maintain, and less prone to errors. That being said, In NodeJS, you can have modules specifically to handle database operations, SaaS functions, and HTTP request processing.</li><li><strong><em>Open/Closed Principle (OCP):</em></strong><br>The term Open/Closed means open for extension and closed for modification. In NodeJS, this can be achieved by designing modules or classes in such way that allows for adding and or implementing new functionality through extension without further modifying existing code.</li><li><strong><em>Liskov Substitution Principle (LSP):</em></strong><br>Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. In NodeJS, technically it’s not directly applicable as we’re not dealing with inheritance, but we can ensure structurally that the behavior of corresponding modules remains consistent across different instances.</li><li><strong><em>Interface Segregation Principle (ISP):</em></strong><br>Clients should not be forced to depend on unused interfaces. This means that interfaces should be small, focused, and specific to the needs by breaking down interfaces into smaller, cohesive units. These can lead to less bloated interfaces and minimize dependencies in-between modules.</li><li><strong><em>Dependency Inversion Principle (DIP):</em></strong><br>High-level modules should not depend on low-level modules and both should depend on abstractions. In NodeJS, this can be achieved by decoupling approach and using dependency injection to provide from external sources. This can lead to code flexibility, easier to test, and less coupled, leading to improved maintainability and scalability.</li></ul><h3><strong>SOLID Implementation In NodeJS</strong></h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/487/1*vrsM9bj0OIbkakjnMo3PjA.png" /><figcaption>Google Sheet Service</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/581/1*prmYZoDywcH5xjJQYcwg8A.png" /><figcaption>Firebase exported function -&gt; getEvents()</figcaption></figure><p><strong><em>Single Responsibility Principle</em></strong></p><ul><li>The <em>“GoogleSheetService”</em> class is responsible for interacting with Google Sheets API to retrieve events data. It encapsulates the functionality related to Google Sheets interaction.</li><li>The Firebase Function handler is responsible for handling HTTP requests, initializing the <em>“GoogleSheetService”</em>, and sending the response. It focuses specifically on request/response handling.</li></ul><p><strong><em>Open/Closed Principle</em></strong></p><ul><li>The <em>“GoogleSheetService”</em> class is open for extension (adding and or implementing new methods for different operations on Google Sheets) but closed for modification (existing methods are not altered when extending functionality).</li></ul><p><strong><em>Liskov Substitution Principle</em></strong></p><ul><li>As far as i’m concern, it’s not directly applicable as i’m not dealing with inheritance, but the code structure ensures that the behavior of <em>“GoogleSheetService”</em> remains consistent across different instances.</li></ul><p><strong><em>Interface Segregation Principle</em></strong></p><ul><li>The <em>“GoogleSheetService” </em>class exposes a cohesive interface (getEvents method) that clients (like the Firebase Function handler) can use without depending on unnecessary methods.</li></ul><p><strong><em>Dependency Inversion Principle</em></strong></p><ul><li>The <em>“GoogleSheetService”</em> class abstracts away the details of interacting with the Google Sheets API. It provides a higher-level interface (getEvents method) that the Firebase Function handler (exports.getEvents) depends on. This follows the said principle because the getEvents() firebase function follow an abstraction rather than concrete implementation for Google Sheets API.</li></ul><h3><strong>Conclusion</strong></h3><p>Embracing SOLID principles not only improves the quality of code but also enhances collaboration and fosters a culture of continuous improvement in software development practices.</p><p><em>Source &amp; Reference : </em><a href="https://www.geeksforgeeks.org/single-responsibility-in-solid-design-principle/"><em>Geeksforgeeks</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b51c5f80fdbb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What It Takes To Be A People Person]]></title>
            <link>https://medium.com/@farras.hafizhudin/what-it-takes-to-be-a-people-person-d21fdd88a870?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/d21fdd88a870</guid>
            <category><![CDATA[teamwork]]></category>
            <category><![CDATA[project-management]]></category>
            <category><![CDATA[people-person]]></category>
            <category><![CDATA[collaborative]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Tue, 27 Feb 2024 12:21:24 GMT</pubDate>
            <atom:updated>2024-02-27T12:21:24.016Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1zJs7Llt2ApIEyLo.jpg" /><figcaption>Source: <a href="https://travanleo.com/wp-content/uploads/2021/08/iStock-1313326821-scaled.jpg">Travanleo</a></figcaption></figure><p>The role of a software developer has expanded besides technical proficiency. Being a “people person” is such an environmental requirements with a unique blend of interpersonal skills that goes well in synergy to the technical expertise mentioned. Let’s dive into what it takes to excel in this aspect and why it’s pretty essential in our today’s software development culture.</p><h3><strong>What Makes Someone A People Person</strong></h3><p>A “people person” in a software developer environment is someone who’s not only possesses strong technical skills but also try to excels in communication, collaboration, and networking. They tends to build with a positive and productive work environment with other team members, concurrent users, and clients in mind. These type of individuals understand every single bit of importance in teamwork, actively gaining feedback, and prioritize thorough communication in every aspect of interactions.</p><h3><strong>How Can Someone Adapt To Being A People Person?</strong></h3><blockquote>Let’s take an example of my current software developer team. We are consisting of seven people each with their own characteristics, thoughts and perspectives.</blockquote><p>We, myself included, believe that in order to meet the requirements of every sprint and releases, have to take the initiate moves in order to kickstart our approach on how the team works and how the client responds. There are a 2 main step that i took to create such environment for my team in order to boost our productivity and effectiveness:</p><ol><li><strong>Collaborative Atmosphere Is A Must: </strong>Effective communication is key in both physical co-working spaces and virtual team environments. I decided to set up a Discord channel for my team that offers various chat channels for team discussions, announcements, and updates, with the intention similar to how coworkers might communicate in person or through messaging platforms in a virtual coworking space. It provides us with a sense of centralized space where my other team members can communicate, share updates, and work together on projects.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/244/1*OnqY7MGcv_QhZ3i6yWNgZw.png" /><figcaption>Our Discord Channel</figcaption></figure><p><strong>2. Neat Workspaces Leads To Better Efficiency: </strong>How we properly set up a workspace in fact, does affect how efficient we work as a team, lets take an example of how i set up a figma workspace for prototyping both mobile and web applications in low and high fidelity designs.</p><p>The primary factor contributing to our improved workflow direction and long-term teamwork proficiency was our meticulous approach at organizing design components and other UI elements into proprietary sections.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cI1t8575v72vosXfxi3teQ.png" /></figure><h3><strong>Conclusion</strong></h3><p>Learning on how to be a people person can thrive some individuals to be collaborative, build meaningful relationships, and drive positive outcomes for their teams and projects. Embracing the role not only enhances individual career even further but also contributes to a more inclusive, productive, and fulfilling work culture as a software development team.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d21fdd88a870" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Basics Of Visual UI : Low & High Fidelity Design Prototypes]]></title>
            <link>https://medium.com/@farras.hafizhudin/creating-low-and-high-fidelity-design-prototypes-in-figma-8e0f90e48cb4?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/8e0f90e48cb4</guid>
            <category><![CDATA[prototype-design]]></category>
            <category><![CDATA[ux-design]]></category>
            <category><![CDATA[ui-design]]></category>
            <category><![CDATA[figma]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Tue, 27 Feb 2024 09:52:07 GMT</pubDate>
            <atom:updated>2024-06-11T00:21:31.049Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*jJHTWzuZ50btKH-e" /><figcaption>Source : <a href="https://www.figma.com/resource-library/high-fidelity-prototyping/">What is high &amp; low fidelity prototyping and how can it help?</a></figcaption></figure><p>When we are working in a software development, we tends to make an app prototype that requires such planning, iteration, and attention to detail. In this particular reason, Figma stands out as a versatile UI &amp; UX platform that facilitates team collaboration throughout the design process. Furthermore, we’ll explore the creation from low fidelity to high fidelity prototypes within a Figma workspace, focusing on both mobile and web applications. We’ll dive deeper into the significance of each phase to bring their visions into our software development process.</p><h3><strong><em>The Basics : Nielsen’s 10 Usability Heuristics</em></strong></h3><p>The basics of user interface design are a set of principles intended to guide designers in creating more effective and user-friendly interfaces. These heuristics were developed by Jakob Nielsen and are widely recognized in the field of usability and human-computer interaction. Here are the said ten heuristics:</p><ol><li><strong>Visibility of system status</strong>: The system should always keep users informed about what is going on through appropriate feedback within a reasonable amount of time.</li><li><strong>User control and freedom</strong>: Users often choose system functions by mistake and will need a clearly marked “emergency exit” to leave the unwanted state without having to go through an extended dialogue. Support undo and redo.</li><li><strong>Consistency and standards</strong>: Users should not have to wonder whether different words, situations, or actions mean the same thing. Follow platform conventions.</li><li><strong>Error prevention</strong>: Even better than good error messages is a careful design that prevents a problem from occurring in the first place. Either eliminate error-prone conditions or check for them and present users with a confirmation option before they commit to the action.</li><li><strong>Recognition rather than recall</strong>: Minimize the user’s memory load by making objects, actions, and options visible. The user should not have to remember information from one part of the dialogue to another. Instructions for use of the system should be visible or easily retrievable whenever appropriate.</li><li><strong>Flexibility and efficiency of use</strong>: Accelerators — unseen by the novice user — may often speed up the interaction for the expert user such that the system can cater to both inexperienced and experienced users. Allow users to tailor frequent actions.</li><li><strong>Aesthetic and minimalist design</strong>: Dialogues should not contain information that is irrelevant or rarely needed. Every extra unit of information in a dialogue competes with the relevant units of information and diminishes their relative visibility.</li><li><strong>Help users recognize, diagnose, and recover from errors</strong>: Error messages should be expressed in plain language (no codes), precisely indicate the problem, and constructively suggest a solution.</li><li><strong>Help and documentation</strong>: Even though it is better if the system can be used without documentation, it may be necessary to provide help and documentation. Any such information should be easy to search, focused on the user’s task, list concrete steps to be carried out, and not be too large.</li></ol><h3><strong>The Necessities of Low Fidelity Prototypes</strong></h3><p>Low fidelity prototypes act as a basic skeletal blueprint for an app, allowing us to throw in concept ideas and mockups. This skeletal blueprint represent layout structures, navigation flows and content placement. Eventually, these designs plays a pivotal role in validating those applied concepts, identifying usability issues, and refining user journeys before investing even further into high fidelity iterations.</p><h3><strong>Crafting Low Fidelity Prototypes</strong></h3><p>With what Figma has to offer, we can utilize its wide variety of robust toolkit, starts with making few sketches out whether it’s wireframes, flow diagrams, or rough mockups. We try to keep up some pace of rapid ideation and iteration in a real-time collaboration that allows seamless communication with other team members, making it efficient brainstorming and design cycles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FHZZ6EXeqLoedOfbJ6p0ZA.png" /><figcaption>Low Fidelity Mobile Designs</figcaption></figure><blockquote>Here we have some of the design based on my team current software development. An app that serve purpose around academic conference that users can interact with for each event details, keynotes and also chat session for asking questions regarding specific events.</blockquote><p>These designs enable us to proceed even further into High Fidelity iterations for more proprietary application that mimics the actual end product.</p><h3><strong>Transitioning to High Fidelity Prototypes</strong></h3><p>At this point, our low fidelity designs marks a significant milestone in the design process. We can proceed to polish the visual aesthetics, interaction details, and content elements of the app, providing our clients with a realistic representation of the end product. Starts with refining typography, incorporate color schemes, add interactive components, and fine-tune UI elements in order to create more immersive experience.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4KZES61L542K31EnGiye4Q.png" /><figcaption>Applied Polishing For High Fidelity Prototypes</figcaption></figure><h3><strong>Testing High Fidelity Prototypes Interactively</strong></h3><p>We set up a prototype flow for users to test out <a href="https://t.maze.co/221401717">here</a>. This prototyping capabilities allow us to mimic a fluid and responsive user experiences, thus gain us valuable insights into user interactions and ensure seamless compatibility across other platform and devices.</p><h3><strong>Conclusion</strong></h3><p>With the technology that is available today, we as a software developer can start prototyping design visions from concept ideas to execution. By creating low and high fidelity prototypes, it allow us to bring and deliver immaculate user experiences and gain insights on what’s work for our client and what are the improvements that we can bring to the table for the end product.</p><p><em>Source:<br></em><a href="https://www.figma.com/resource-library/low-fidelity-prototyping/"><em>https://www.figma.com/resource-library/low-fidelity-prototyping/</em></a><em><br></em><a href="https://www.figma.com/resource-library/high-fidelity-prototyping/"><em>https://www.figma.com/resource-library/high-fidelity-prototyping/</em></a><em> </em><a href="https://www.nngroup.com/articles/ten-usability-heuristics/"><em>https://www.nngroup.com/articles/ten-usability-heuristics/</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8e0f90e48cb4" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Defining Test-Driven Development (TDD) And Its Implementation]]></title>
            <link>https://medium.com/@farras.hafizhudin/defining-test-driven-development-tdd-and-its-implementation-7efb6402388b?source=rss-abc69b449cfe------2</link>
            <guid isPermaLink="false">https://medium.com/p/7efb6402388b</guid>
            <category><![CDATA[ppl-fasilkom-ui]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[test-driven-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Farras Hafizhudin Indra Wijaya]]></dc:creator>
            <pubDate>Tue, 27 Feb 2024 04:38:17 GMT</pubDate>
            <atom:updated>2024-02-27T04:38:17.244Z</atom:updated>
            <content:encoded><![CDATA[<p>How do we define Test-Driven Development? how can we achieve the reliability and stability code with such deadlines, requirements and complex systems? That’s what Test-Driven Development actually encourage us, offering a structured approach to build software that prioritizes testing from the outset. Furthermore, we’ll dive into the principles, benefits, and its implementation to understand it thoroughly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/892/0*ealE61sFenHrpqBL.png" /><figcaption>Source : <a href="https://www.spiceworks.com/tech/devops/articles/what-is-tdd/">What Is TDD (Test Driven Development)?</a></figcaption></figure><p>At its core, Test-Driven Development is a software development technique where tests are written before the actual code implementation. This iterative process follows three main cycle:</p><ol><li><strong>Write a Test</strong>: We, developers, start our requested feature by writing a test that defines the desired behavior of a small unit of code, typically a function or method. This specific test is set to fail by design since our implementation doesn’t yet to exist.</li><li><strong>Write the Code</strong>: Next, we can start to implement and write the code required to make the test pass. The focus here is solely on fulfilling the requirements of the test, without considering additional functionalities.</li><li><strong>Refactor the Test</strong>: Once the test passes, we then able to refactor the code to improve its structure, readability, and efficiency while ensuring that all tests continue to pass.</li></ol><h3>The Benefits of Test-Driven Development</h3><ol><li><strong>Improved Code Quality</strong>: We gain a clear understanding of the expected behavior of their code, resulting in cleaner, more reliable implementations by doing the test upfront.</li><li><strong>Faster Feedback Loop</strong>: Tests are usually automated and executed frequently so that we can identify and fix issues early in the development process, reducing the likelihood of bugs produced in production.</li><li><strong>Enhanced Design</strong>: Writing tests first forces us to think about interfaces and interactions, leading to more ‘cohesive’ and ‘maintainable’ software designs.</li></ol><h3><strong>TDD’s Implementation on NodeJS Project</strong></h3><p>First thing first, my requirement is to make an API that fetch google spreadsheets data. So we can try to define a positive test case with onSuccess() request that take “HTTP 200 OK” as a response.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/546/1*nlVqPje_CUVBbd7dZZWSMw.png" /></figure><p>Next, we can describe the test function with its context.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*8-nMLPosbeJfZN1vigcAnw.png" /><figcaption>set getEvents() as test’s context</figcaption></figure><p>With such test case, it will throws us an error that getEvents() is not defined since we haven’t implement yet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*nA88degUDYjJO5LHXF0tYQ.png" /><figcaption>getEvents() is not yet expected to equal to HTTP 200 OK as a response</figcaption></figure><p>Now we are on the right track to proceed on writing and implementing the required code for the test. Here we have a listEvents() function to fetch specified events from such spreadsheet ID and gain an Array&lt;Event&gt; as a return.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/563/1*MXSX3EUkKoSVChlG3yksKw.png" /><figcaption>listEvents() fetch event from spreadsheet and return it as Array&lt;Event&gt;</figcaption></figure><p>After that, we proceed to implement &amp; export the getEvents() function with the “200 OK” as response status and the Array&lt;Event&gt; as its body.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/614/1*miV_1POVeffBlnxm3XPZ_Q.png" /><figcaption>exported getEvents()</figcaption></figure><p>Last but not least, we refactor our previous tests to call and verify its response with our corresponding onSuccess verification.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/502/1*NJH0a3bPHLU8C8skj5zuDw.png" /><figcaption>refactored test</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/707/1*pSZK-hBhsWwJOn8-eqH8ng.png" /><figcaption>onSuccess positive test case passed</figcaption></figure><p>As we can see, our test succeeded with the exported getEvents() function returning “200 OK” as its response and is expected by our verify onSuccess request.</p><h3><strong>Conclusion</strong></h3><p>Test-Driven Development is more than just a methodology; it encourages us in order to write better software, respond to change more effectively, and deliver value to our users. Additionally, it may require initial adjustments in such variety of workflows but the long-term benefits far outweigh the investment, making it a valuable practice for any software development team.</p><p><em>Source: </em><a href="https://www.spiceworks.com/tech/devops/articles/what-is-tdd/"><em>https://www.spiceworks.com/tech/devops/articles/what-is-tdd/</em></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7efb6402388b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>